当前位置: 首页 > Web前端 > HTML5

你应该知道的5种TypeScript设计模式_0

时间:2023-04-05 19:19:08 HTML5

作者: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{返回rnnewBicycle()}}///用户代码...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("---Nowlet'sgoswimming---")constswimmingDog=newSwimmingAnimal(dog)swimmingDog.move()注意几个细节:现实上,SuperDecorator类扩展了Animal类,Dog类扩展了同一个类。这是因为装饰器需要提供与它试图装饰的类相同的公共接口。SuperDecorator类是抽象的,这意味着它没有被使用,它只是用来定义一个构造函数,该构造函数将在受保护的属性中保留原始对象的副本。公共接口的覆盖是在自定义装饰器内部完成的。SuperAnimal和SwimmingAnimal是实际的装饰器,它们是添加额外行为的装饰器。进行此设置的好处在于,由于所有装饰器也间接扩展了Animal类,如果您想将这两种行为混合在一起,您可以这样做:constsuperSwimmingDog=newSwimmingAnimal(superDog)superSwimmingDog.move()Composite(组合)关于Composite模式,其实就是组合模式,也叫局部整体模式。这种模式在我们的生活中经常会用到。比如你写过一个前端页面,肯定是用

这样的标签定义了一些格式,然后将这些格式相互组合起来,递归的组织成相应的结构。这种方法实际上是一种组合,将一些组件拼接成一个整体。这种模式的有趣之处在于它不是简单的一组对象,它可以包含实体或实体组,每个组可以同时包含更多组,这就是我们所说的树。看一个例子:interfaceIProduct{getName():stringgetPrice():number}classProductimplementsIProduct{privateprice:numberprivatename:stringconstructor(name:string,price:number){this.name=namethis.price=price}publicgetPrice():number{returnthis.price}publicgetName():string{returnthis.name}}classBoximplementsIProduct{私有产品:IProduct[]=[]contructor(){this.products=[]}publicgetName():string{return"Aboxwith"+this.products.length+"products"}add(p:IProduct):void{console.log("添加一个",p.getName(),"tothebox")this.products.push(p)}getPrice():number{returnthis.products.reduce((curr:number,b:IProduct)=>(curr+b.getPrice()),0)}}//使用代码...constbox1=newBox()box1.add(newProduct("Bubblegum",0.5))box1.add(newProduct("SamsungNote20",1005))constbox2=新盒子()box2.add(newProduct("三星电视20in",300))box2.add(newProduct("三星电视50in",800))box1.add(box2)console.log("总价:",box1.getPrice())在上面的例子中,我们可以将产品放入Box中,也可以将Box放入其他的Box中,这是一个经典的组合例子。由于我们要实现的是获取完整的发货价格,所以我们需要在大箱子中添加每个元素的价格(包括每个小箱子的价格)。以上操作的结果:添加泡泡糖到盒子中添加三星Note20到盒子中添加三星电视20英寸添加三星电视50英寸到盒子中添加2个产品的盒子总价:2105.5因此,processingfollows当你有多个相同接口的对象时考虑使用这个模式。通过将复杂性隐藏在单个实体(组合本身)中,您会发现它有助于简化您与团队的互动方式。今天的分享就到这里,感谢大家的收看,我们下期再见。原文:https://blog.bitsrc.io/design...无法实时获知代码部署后可能出现的bug。之后为了解决这些bug,花费了大量的时间在日志调试上。这里给大家推荐一款好用的BUG监控工具Fundebug。交流有梦想,有干货,微信搜索【大千世界】关注这位凌晨还在洗碗的洗碗智者。本文GitHubhttps://github.com/qq44924588...已收录,有完整的测试站点、资料和我的一线厂商访谈系列文章。