常用的几个设计模式
- 0
为JavaScript设计面向对象系统之初,Brendan Eich 就没有打算在JavaScript中加入类的概念。
在以类为中心的面向对象编程语言中,类和对象的关系可以想象成铸模和铸件的关系,对象总是从类中创建而来。而在原型编程的思想中,类并不是必需的,对象未必需要从类中创建而来, 一个对象是通过克隆另外一个对象所得到的。
原型模式是用于创建对象的一种模式,如果我们想要创建一个对象, 一种方法是先指定它的类型,然后通过类来创建这个对象。原型模式选择了另外一种方式,我们 不再关心对象的具体类型,而是找到一个对象,然后通过克隆来创建一个一模一样的对象。
原型模式的实现关键,是语言本身是否提供了clone 方法。ECMAScript 5 提供了Object.create
方法,可以用来克隆对象。
但实际上,不需要调用Object.create
,我们在JavaScript 遇到的每个对象,都是从Object.prototype
对象克隆而来的,Object.prototype
就是它们的原型。比如下面的obj1 对象和obj2 对象:
JavaScript
在JavaScript 语言里,我们并不需要关心克隆的细节,因为这是引擎内部负责实现的。我们所需要做的只是显式地调用var obj1 = new Object() 或者 var obj2 = 。此时,引擎内部会从 Object.prototype
上面克隆一个对象出来,我们最终得到的就是这个对象。
再来看看如何用new 运算符从构造器中得到一个对象,下面的代码我们再熟悉不过了:
JavaScript
我们调用了new Person() ,但在这里Person并不是类,而是函数构造器,JavaScript的函数既可以作为普通函数被调用,也可以作为构造器被调用。当使用new 运算符来调用函数时,此时的函数就是一个构造器。
在Chrome 和Firefox 等向外暴露了对象__proto__属性的浏览器下,我们可以通过下面这段代码来理解new运算的过程:
JavaScript
对于原型,我们很清楚的一点是当一个对象无法响应某个请求的时候,它会顺着原型链把请求传递下去,直到遇到一个可以处理该请求的对象为止。
保证一个类仅有一个实例,并提供一个访问它的全局访问点
JavaScript
用于替换很多
if
else
的场景
改造前
JavaScript
改造后
JavaScript
状态模式
的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变。
我们来想象这样一个场景:有一个电灯,电灯上面只有一个开关。当电灯开着的时候,此时按下开关,电灯会切换到关闭状态;再按一次开关,电灯又将被打开。同一个开关按钮,在不同的状态下,表现出来的行为是不一样的。
首先给出不用状态模式的电灯程序实现:
JavaScript
令人遗憾的是,这个世界上的电灯并非只有一种。许多酒店里有另外一种电灯,这种电灯也只有一个开关,但它的表现是:第一次按下打开弱光,第二次按下打开强光,第三次才是关闭电灯。而这些必须改造上面的代码来完成这种新型电灯的制造。
但将状态改变的逻辑全部写在buttonWasPressed中存在以下问题:
现在我们学习使用状态模式改进电灯的程序。状态模式的关键是把事物的每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部,所以button被按下的的时候,只需要在上下文中,把这个请求委托给当前的状态对象即可,该状态对象会负责渲染它自身的行为。
JavaScript
执行结果跟之前的代码一致,但是使用状态模式的好处很明显,它可以使每一种状态和它对应的行为之间的关系局部化,这些行为被分散和封装在各自对应的状态类之中,便于阅读和管理代码。
另外,状态之间的切换都被分布在状态类内部,这使得我们无需编写过多的if、else条件分支语言来控制状态之间的转换。
适配器模式
的作用是解决两个软件实体间的接口不兼容的问题。使用适配器模式之后,原本由于接口不兼容而不能工作的两个软件实体可以一起工作。
假设我们要用googleMap和baiduMap分别以各自的方式在页面中展现地图。
JavaScript
由于两个地图的展示方法不同,所以不能直接调用renderMap函数,因此我们要为百度地图提供一个适配器。这样我们就可以同时渲染2个地图了。
JavaScript
状态变化需要通知其他事件
JavaScript