作者:FernandoDoglio译者:前端小智。本文已收录到GitHubhttps://github.com/qq449245884/xiaozhi,里面有完整的测试站点、资料和我的一线厂商访谈系列文章。设计模式是帮助开发人员解决问题的模板。本书涵盖的模式太多,而且它们往往针对不同的需求。但是,它们可以分为三个不同的组:结构模式处理不同组件(或类)之间的关系并形成新结构以提供新功能。结构模式的示例有Composite、Adapter和Decorator。行为模式将组件之间的共同行为抽象为一个独立的实体。行为模式的例子有命令、策略和我个人最喜欢的:观察者模式。创建型模式专注于类的实例化,使我们更容易创建新的实体。我说的是工厂方法、单例和抽象工厂。单例模式单例模式可能是最著名的设计模式之一。这是一种创建型模式,因为它确保无论我们尝试实例化一个类多少次,我们都只有一个实例可用。处理数据库连接之类的事情可以是单例的,因为我们一次只想处理一个,而不必在每个用户请求时都重新连接。类MyDBConn{受保护的静态实例:MyDBConn|null=nullprivateid:number=0constructor(){this.id=Math.random()}publicgetID():number{returnthis.id}publicstaticgetInstance():MyDBConn{if(!MyDBConn.instance){MyDBConn.instance=newMyDBConn()}returnMyDBConn.instance}}constconnections=[MyDBConn.getInstance(),MyDBConn.getInstance(),MyDBConn.getInstance(),MyDBConn.getInstance(),MyDBConn.getInstance()]connections.forEach(c=>{console.log(c.getID())})现在类虽然不能直接实例化,但是使用getInstance方法可以保证不会出现多实例。在上面的示例中,您可以看到包装数据库连接的伪类如何从这种模式中受益。这个例子表明,无论我们调用多少次getInstance方法,连接总是相同的。以上操作的结果:0.40470872509907130.40470872509907130.40470872509907130.40470872509907130.4047087250990713工厂模式工厂模式是一种创建模式,和单例模式一样。然而,这种模式并不直接作用于我们关心的对象,而只是管理它的创建。解释一下:假设我们通过编写代码来模拟一辆行驶中的车辆。有许多类型的交通工具,例如汽车、自行车和飞机。移动代码应该封装在每个车辆类中,但是调用它们的移动方法的代码可以通用。这里的问题是如何处理对象创建?可以有一个具有3个方法的创建者类,或者一个接收参数的方法。在任何一种情况下,扩展该逻辑以支持创建更多车辆都需要不断增加相同的类别。但是,如果您决定使用工厂方法模式,那么您可以这样做:现在,创建新对象所需的代码被封装到一个新类中,每个类对应一种车辆类型。这样可以确保如果将来需要添加车辆,只需添加一个新类,而无需修改任何已经存在的内容。让我们看看如何使用TypeScript实现这一点:move():void{console.log("Movingthebicycle!")}}classPlaneimplementsVehicle{publicmove():void{console.log("Flyingtheplane!")}}//VehicleHandler是“抽象的”"因为没有人会实例化它//我们要扩展它并实现抽象方法abstractclassVehicleHandler{//这是真正的处理程序需要实现的方法publicabstractcreateVehicle():VehiclepublicmoveVehicle():void{constmyVehicle=this.createVehicle()myVehicle.move()}}classPlaneHandlerextendsVehicleHandler{publiccreateVehicle():Vehicle{returnnewPlane()}}classCarHandlerextendsVehicleHandler{publiccreate:VehicleVehicle{returnnewCar()}}classBicycleHandlerextendsVehicleHandler{publiccreateVehicle():Vehicle{returnnewBicycle()}}///用户代码...constplanes=newPlaneHandler()constcars=newCarHandler()planes.moveVehicle()cars.moveVehicle()上面有很多代码,但是我们可以通过上图来理解。本质上最后,我们关心的是自定义处理程序,这里我们称它们为处理程序,而不是创建者,因为它们不仅仅是创建的对象,它们也有逻辑,使用它们(moveVehicle方法)。这种模式的美妙之处在于,如果你想添加一种新的车辆类型,你所要做的就是添加它的车辆类和它的handler类,而无需增加任何其他类的LOC。观察者模式在所有模式中,我最喜欢的是观察者模式,因为我们可以实现它的行为类型。它是如何工作的?本质上,该模式声明您有一组观察者对象,这些观察者对象将对被观察实体的状态变化做出反应。为实现这一点,它负责在被观察端收到更改后通过调用其方法之一来通知其观察者。在实践中,这个模式的实现比较简单,先快速看一下代码再回顾一下观察者:Observer[]=[]protectedstate:InternalState={event:""}publicaddObserver(o:Observer):void{this.observers.push(o)}protectednotify(){this.observers.forEach(o=>o.update(this.state))}}classConsoleLoggerextendsObserver{publicupdate(newState:InternalState){console.log("Newinternalstateupdate:",newState)}}classInputElementextendsObservable{publicclick():void{this.state={event:"click"}this.notify()}}constinput=newInputElement()input.addObserver(newConsoleLogger())input.click()可以看到,通过两个一个抽象类,我们可以在其中定义Observer,它将表示一个对Observable实体的变化做出反应的对象。在上面的示例中,我们假设有一个被单击的InputElement实体(类似于您在前端有一个HTML输入字段的方式),以及一个记录控制台发生的所有事情的ConsoleLogger。这种模式的美妙之处在于它允许我们理解Observable的内部状态并对其做出反应,而不会弄乱其内部代码。我们可以不断添加做其他事情的观察者,甚至是对特定事件做出反应的观察者,并让它们的代码决定如何处理每个通知。装饰器模式装饰器模式试图在运行时向现有对象添加行为。从某种意义上说,我们可以将其视为动态继承,因为即使我们没有创建新类来添加行为,我们也正在创建具有扩展功能的新对象。这样想:假设我们有一个带有move方法的Dog类,现在您想扩展它的行为,因为我们想要一只超级狗和一只会游泳的狗。通常,我们需要在Dog类中添加移动行为,然后通过两种方式扩展该类,SuperDog和SwimmingDog类。然而,如果我们想混合这两者,我们又必须创建一个新类来扩展它们的行为,但是,还有更好的方法。组合允许我们将自定义行为封装在不同的类中,然后使用此模式通过将原始对象传递给它们的构造函数来创建这些类的新实例。让我们看一下代码:abstractclassAnimal{abstractmove():void}abstractclassSuperDecoratorextendsAnimal{protectedcomp:Animalconstructor(decoratedAnimal:Animal){super()this.comp=decoratedAnimal}abstractmove():void}classDogextendsAnimal{publicmove():void{console.log("移动狗...")}}classSuperAnimalextendsSuperDecorator{publicmove():void{console.log("开始飞行...")this.comp.move()console.log("Landing...")}}classSwimmingAnimalextendsSuperDecorator{publicmove():void{console.log("跳入水中...")this.comp.move()}}constdog=newDog()console.log("---非装饰尝试:")dog.move()console.log("---飞行装饰器---")constsuperDog=newSuperAnimal(dog)superDog.move()console.log("---现在让我们去游泳---")constswimmingDog=newSwimmingAnimal(dog)swimmingDog.move()注意一些细节:事实上,SuperDecorator类扩展了Animal类,与Dog类扩展的是同一个类。这是因为装饰器需要提供与它试图装饰接口的类相同的public。SuperDecorator类是抽象的,这意味着它没有被使用,它只是用来定义一个构造函数,该构造函数将在受保护的属性中保留原始对象的副本。公共接口的覆盖是在自定义装饰器内部完成的。SuperAnimal和SwimmingAnimal是实际的装饰器,它们是添加额外行为的装饰器。进行此设置的好处在于,由于所有装饰器也间接扩展了Animal类,如果您想将这两种行为混合在一起,您可以这样做:constsuperSwimmingDog=newSwimmingAnimal(superDog)superSwimmingDog.move()Composite(组合)关于Composite模式,其实就是组合模式,也叫局部整体模式。这种模式在我们的生活中经常会用到。比如你写过一个前端页面,肯定是用
