最近在看Head First设计模式,想好好学一下设计模式相关的知识。这本书要求看书的人须要会java和OO(即面向对象)设计原则,好在二者在学校都学过。可是平时在写js和业务代码的时候不多用到相关的知识,而咱们经常使用到的库和框架,却无处不存在着这些知识,因此想本身写一些库或者框架的人,学会设计模式仍是颇有必要的。我以为设计模式和算法有一些类似之处,它们都是一种思想,是一种解决方法。设计模式不是具体的代码和具体的实现,而是和算法同样,是以一种思想存在,当咱们想实现某种功能,或者构思框架和库的时候,相关的解决方案便浮如今你的脑海里,因此说设计模式不是说就必定是一种模式,有多是模式的组合,模式基础上的变化。固然,以上所说也只是我看了前几章的想法。最主要的仍是书中所写的实现代码皆是java,因此仍是想着用js写一遍,毕竟js看起来不太像是拿来写面向对象的(不过es6已经有Class了)。因此写这个也权当作是自我记录吧。java
策略模式定义了算法族,分别封装起来,让它们之间能够互相替换,此模式让算法的变化独立于使用算法的客户。
看了这个正式定义后多是很差理解的,不过不要紧,讲个书里的例子就明白了。es6
小李的公司要求他开发一套模拟鸭子的游戏,所以他写了个超类(即父类)Duck,并让各类鸭子继承此超类。(如下代码皆用js来编写)算法
class Duck { quack () {} swim () {} display () {} }
他给鸭子超类定义了鸭子叫、游泳、展现方法。可是因为每一种鸭子的外观不一样,所以在这里的定义是抽象方法(即在超类中不实现,交由子类负责实现,但在js中并无这种定义),而后在每一个鸭子子类中进行实现本身的display方法。编程
就这样,小李完成了一个简单的模拟鸭子游戏。可是,次日,产品经理让小李给鸭子加一个飞行的方法。小李心想这还不简单吗,在Duck超类里加一个fly () {}
方法就完事了,这就是面向对象的威力。设计模式
然而,在次日的演示中,产品经理惊讶的发现‘橡皮鸭子’也能在屏幕飞来飞去。小李心想糟糕了,因而赶忙在橡皮鸭的类中进行了fly方法覆盖,虽然暂时解决了问题,可是一想到往后还要添加各类各样的鸭子,每只️鸭子的飞行方法和叫声都不同,难道每次添加新类的时候都要去覆盖和检查吗?框架
设计原则: 找出应用中可能须要变化的地方,而后将它们独立出来,不要与那些不须要变化的代码混在一块儿。
根据这个原则来分析鸭子的行为,就目前来看,鸭子叫和飞行方法是会随着鸭子的不一样而改变的,所以须要将两个方法取出来,创建新的类来表明行为。那为何不取出display呢?这件事书里并无提到,可是稍稍分析便知道了,display对于每一个鸭子子类来讲都是一定须要设置的,又不存在相同的状况,所以没有潜在的复用可能性,就是独立成display类也仍是依附于特定鸭子子类的,所以没有必要将展现方法取出来。this
设计原则: 针对接口编程,而不是针对实现编程。
这里的接口指的是面向对象里的一个关键字interface
,接口就像是一个定义好了全部方法的类,可是其中的每个方法都不进行实际代码的实现,而是交由继承它的子类来实现方法。它是一种约束,继承了它的子类都必须实现。所以,当咱们在使用接口的时候,咱们能确定的去使用继承了某个接口的类的方法,即就是方法必然存在。所以在编写的时候无需关心具体的代码实现(以上是我的的理解)。设计
所以书中分别建了FlyBehavior
和QuackBehavior
这两个接口,不过js中并无接口这种定义,可是js中并无与接口功能相似的方法存在,只能写个类去代替它,可是这个类并无约束效力,所以从这里也能够看出来TS的诞生缘由。code
class FlyBehavior { fly () { console.log('未定义飞行方法'); } } class FlyWithWings extends FlyBehavior { fly () { console.log('FlyWithWings'); } } class FlyNoWay extends FlyBehavior { fly () { console.log('FlyNoWay'); } }
QuackBehavior
的实现与上面相似。orm
这样的设计,可让飞行和呱呱叫的动做被其余对象复用,由于这些行为已经与鸭子类无关了。而咱们能够新增一些行为,不会影响到既有的行为类,也不会影响使用到飞行行为的鸭子类。
此时再来重写编写鸭子类,就变成了以下。
class Duck { flyBehavior quackBehavior swim () {} display () {} setFly (fly) { this.flyBehavior = fly; } setQuack (quack) { this.quackBehavior = quack; } performFly () { this.flyBehavior.fly(); } performQuack () { this.quackBehavir.quack(); } }
能够看到此时咱们再也不在意具体的fly方法或者quack 方法是怎么样的,咱们只须要去调用方法便可,同时还能够在运行时进行方法的替换,经过调用setQuack
与setFly
方法。
此时来写一个具体的鸭子类。
class MallardDuck extends Duck { constructor () { super(); this.setQuack(new Quack()); this.setFly(new FlyWithWings()); } display () {} // 记得重写 }
到这里大概差很少大概就可以理解策略模式是怎么样的了,有时候咱们能够把一组行为认为是一族算法,而后封装起来,互相独立,能够随意替换,这差很少就是策略模式的面貌了。
设计原则:多用组合,少用继承。