设计模式的定义:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案
当然我们可以用一个通俗的说法:设计模式是解决某个特定场景下对某种问题的解决方案。因此,当我们遇到合适的场景时,我们可能会条件反射一样自然而然想到符合这种场景的设计模式。
单例模式
单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class CreateUser { constructor(name) { this.name = name; this.getName(); } getName() { return this.name; } }
var ProxyMode = (function() { var instance = null; return function(name) { if (!instance) { instance = new CreateUser(name); } return instance; }; })();
var a = ProxyMode('aaa'); var b = ProxyMode('bbb');
console.log(a === b);
|
策略模式
策略模式的定义:定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。
策略模式的目的就是将算法的实现分离开来。
一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类(可变),策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类 Context(不变),Context 接受客户的请求,随后将请求委托给某一个策略类。要做到这一点,说明 Context 中要维持对某个策略对象的引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var levelObj = { A(money) { return money * 4; }, B(money) { return money * 3; }, C(money) { return money * 2; } };
var calculateBouns = function(level, money) { return levelObj[level](money); }; console.log(calculateBouns('A', 10000));
|
代理模式
代理模式的定义:为一个对象提供一个代用品或占位符,以便控制对它的访问。
常用的虚拟代理形式:某一个花销很大的操作,可以通过虚拟代理的方式延迟到这种需要它的时候才去创建(例:使用虚拟代理实现图片懒加载)
图片懒加载的方式:先通过一张 loading 图占位,然后通过异步的方式加载原图,等原图加载好了再把图片加载到 img
标签里面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| var imgFunc = (function() { var imgNode = document.createElement('img'); document.body.appendChild(imgNode); return { setSrc: function(src) { imgNode.src = src; } }; })(); var proxyImage = (function() { var img = new Image(); img.onload = function() { imgFunc.setSrc(this.src); }; return { setSrc: function(src) { imgFunc.setSrc('./loading,gif'); img.src = src; } }; })(); proxyImage.setSrc('./pic.png');
|
使用代理模式实现图片懒加载的优点还有符合单一职责原则。减少一个类或方法的粒度和耦合度。
中介者模式
中介者模式的定义:通过一个中介者对象,其他所有的相关对象都通过该中介者对象来通信,而不是相互引用,当其中的一个对象发生改变时,只需要通知中介者对象即可。通过中介者模式可以解除对象与对象之间的紧耦合关系。
例如:现实生活中,航线上的飞机只需要和机场的塔台通信就能确定航线和飞行状态,而不需要和所有飞机通信。同时塔台作为中介者,知道每架飞机的飞行状态,所以可以安排所有飞机的起降和航线安排。
中介者模式适用的场景:例如购物车需求,存在商品选择表单、颜色选择表单、购买数量表单等等,都会触发 change
事件,那么可以通过中介者来转发处理这些事件,实现各个事件间的解耦,仅仅维护中介者对象即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| var goods = { 'red|32G': 3, 'red|64G': 1, 'blue|32G': 7, 'blue|64G': 6 }; var colorSelect = document.getElementById('colorSelect'); var memorySelect = document.getElementById('memorySelect'); var numSelect = document.getElementById('numSelect');
var mediator = (function() { return { changed: function(obj) { switch (obj) { case colorSelect: break; case memorySelect: break; case numSelect: break; } } }; })(); colorSelect.onchange = function() { mediator.changed(this); }; memorySelect.onchange = function() { mediator.changed(this); }; numSelect.onchange = function() { mediator.changed(this); };
|
装饰者模式
装饰者模式的定义:在不改变对象自身的基础上,在程序运行期间给对象动态地添加方法。
例如:现有 4 种型号的自行车分别被定义成一个单独的类,如果给每辆自行车都加上前灯、尾灯、铃铛这 3 个配件,如果用类继承的方式,需要创建 4*3=12
个子类。但如果通过装饰者模式,只需要创建 3 个类。
装饰者模式适用的场景:原有方法维持不变,在原有方法上再挂载其他方法来满足现有需求;函数的解耦,将函数拆分成多个可复用的函数,再将拆分出来的函数挂载到某个函数上,实现相同的效果但增强了复用性。
例:用 AOP 装饰函数实现装饰者模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Function.prototype.before = function(beforefn) { var self = this; return function() { beforefn.apply(this, arguments); return self.apply(this, arguments); }; }; Function.prototype.after = function(afterfn) { var self = this; return function() { var ret = self.apply(this, arguments); afterfn.apply(this, arguments); return ret; }; }; var func = function() { console.log('2'); };
var func1 = function() { console.log('1'); }; var func3 = function() { console.log('3'); };
func = func.before(func1).after(func3); func();
|
引用
JavaScript 设计模式