We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TOC]
保证一个类仅有一个实例,并提供一个访问它的全局访问点。应用:显示登录浮窗
var Singleton = function(name) { this.name = name; this.instance = null; } Singleton.prototype.sayName = funciton() { } Singleton.getInstance = function() { if (!this.instance) { return new Singleton(); } return this.instance } var a = Singleton.getInstance('a'); var b = Singleton.getInstance('b'); console.log(a === b) // true
实现一个透明的单例类,用户从这个类中创建对象的时候,可以像使用其他类一样
var CreateDiv = (function() { var instance; var CreateDiv = function() { if (instance) { return instance; } this.html = html; this.init(); return instance = this; } CreateDiv.prototype.init = function() { var div = document.createElement('div'); div.innerHTML = this.html; document.body.appendChild(div); } return CreateDiv })();
var CreateDiv = function() { this.html = html; this.init(); } CreateDiv.prototype.init = function() { var div = document.createElement('div'); div.innerHTML = this.html; document.body.appendChild(div); } return CreateDiv var ProxySingleton = (function(html) { var istance; if (!instance) { instance = new CreateDiv(html); } return instance })()
创建方式:
var MyApp = { }; MyApp.namespace = function(name) { var parts = name.split('.'); var current = MyApp; for (var i = 0, len = parts.length; i < len; i++) { if (!current[parts[i]]) { current[parts[i]] = {} } current = current[parts[i]]; } } MyApp.namespace('event'); MyApp.namespace('dom.style'); // MyApp = { // event: {}, // dom: { // style: {} // } // }
采用事件机制,来创建,但是不符合单一职责原则,如果要创建其他标签,就得重写
var createDiv = (function() { var div = null; return function() { if (!div) { div = document.createElement('div'); div.innerHTML = 'div'; div.style.display = 'none'; document.appendChild(div); return div; } return div; } })(); document.querySelector('btn').onclick = function() { var player = createDiv(); player.style.display = 'block' }
var getSingle = function(fn) { var result; return result || result = fn.apply(this, arguments) }
定义一系列算法,并将它们封装成策略类,算法被封装在策略类内部的方法里,使它们可以相互替换。在客户对Context发起请求时,Context总是将请求委托给这些策略对象中间的某一个计算
var performanceS = function() { } performanceS.prototype.calculate = function(salary) { return salary*4 } var performanceA = function() { } performanceA.prototype.calculate = function(salary) { return salary*4 } var Bonus = function() { this.salary = null; this.strategy = null; } Bonus.prototype.setSalary = function(salary) { this.salary = salary; } Bonus.prototype.setStrategy = function(strategy) { this.strategy = strategy; } Bonus.prototype.getBonus = function() { return this.strategy.calculate(this.salary); }
优化方案:
体现了多态的特性
var strategies = { S: function(salary) { return salary*4 }, A: function(salary) { return salary*3 } } var calculateBonus = function(level, salary) { return strategies[level](salary) }
应用:
缺点:
当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象。
代理B帮助代理A过滤掉一些请求
把一些开销很大的对象,延迟到真正需要它的时候才去创建。
var myImage = (function() { var img = new Image(); document.appendChild(img) return { setSrc: function(src) { img.src = src; } } })() var proxyImage = (function() { var img = new Image(); img.onload = function() { myImage.setSrc(this.src); } return { setSrc: function(src) { myImage.setSrc = 'loading.gif'; img.src = src; } } })() proxyImage.setSrc('real-img.jpg')
// 缓存代理,通过传入方法,也可以为各种计算进行代理 var mult = function() { var result = 1; for (var i = 0, len = arguments.length; i < len; i++) { result *= arguments[i]; } return; } var proxyMult = (function() { var cache = {}; return function() { var args = Array.prototype.join.call(arguments, ','); if (args in cache) { return cache[args]; } return cache[args] = mult.apply(this, arguments); } })(); proxyMult(2, 3, 4);
还能用于ajax异步请求数据,比如:分页。
提供一个方法有序的访问一个聚合对象的每一个元素,又不用关心对象的内部构造
var each = function(arr, callback) { for (var i = 0, len = arr.length; i < len; i++) { callback.call(arr[i], i, arr[i]); } }
上述的each函数,就是一个内部迭代器,each函数内部已经定义好了规则
显示地跌代下一个元素
function Iterator(arr) { let index = 0; function next() { index++; } function isDone() { return index >= arr.length; } function getCurrent() { return arr[index]; } return { next, isDone, getCurrent } } let iterator1 = Iterator([1, 2, 3]); let iterator2 = Iterator([1, 2, 3]); function compare(iterator1, iterator2) { while (!iterator1.isDone() && !iterator2.isDone()) { if (iterator1.getCurrent() !== iterator2.getCurrent()) { throw new Error('iterator1 !== iterator2'); } iterator1.next(); iterator2.next(); } }
区分数组
迭代器提供有序访问,所以顺序是可以设定的
用break来中止迭代器
又叫观察者模式,定义了一对多的依赖关系
作用:
class CustomEvent { constructor() { this.events = {}; } on(evName, evFn) { let evArr = this.events[evName] = this.events[evName] || []; if (!isFunction(evFn) || evArr.indexOf(evFn) > -1) { return false; } evArr.push(evFn); return true; } un(evName, evFn) { let evArr = this.events[evName]; if (!evArr) { return false; } if (!evFn || !isFunction(evFn)) { this.events[evName] = null; return true; } let index = evArr.indexOf(evFn); let result = index >= 0; result && evArr.splice(index, 1); return result; } emit(evName, ...args) { let evArr = this.events[evName]; if (!Array.isArray(evArr)) { return false; } evArr.forEach((val, index) => { val.apply(this, args); }); return true; } }
不是的,如qq离线消息。建立一个离线存放事件的堆栈,当事件发布的时候,如果此时还没有订阅者来订阅这个事件,暂时把发布事件的动作包裹在一个函数里,这些包装函数将被存入堆栈,等到有对象来订阅时,遍历堆栈执行包装函数。
给Event对象提供创建命名空间的功能
命令模式中的命令指的是一个执行某些特定事情的指令
有时候需要向某些对象发送请求,但是不知道请求的接受者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合来设计程序,是的请求发送者和请求接收者能够消除彼此之间的耦合关系。
var MenuBar = { refresh: function() { console.log('refresh') } } var SubBar = { add: function() { console.log('add') } } function RefreshMenuBarCommand(receiver) { this.receiver = receiver; } RefreshMenuBarCommand.prototype.execute = function() { this.receiver.refresh() } function AddMenuBarCommand(receiver) { this.receiver = receiver; } AddMenuBarCommand.prototype.execute = function() { this.receiver.add() } var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar); var addMenuBarCommand = new AddMenuBarCommand(SubBar); function setCommand(button, command) { button.onclick = function() { command.execute(); } } setCommand(document.querySelector('.btn-1'), refreshMenuBarCommand)
提供一个undo方法,如小球移动,每次移动记录上一次位置,这样在undo方法中就能回到上一次位置。
提供一个队列,将每次命令入队列,重做时出队
第一个完成再进行第二个
一组命令的集合
var Macro = function() { execute: function() { for (var i = 0; i < this.list.length; i++) { this.list[i].execute(); } } }
举例:宏命令对象和普通命令对象,采用深度优先遍历这些命令并execute
用途:
注意:
好处:
抽象类,需要继承实现的模式,通过封装变化提高系统的扩展性。
重写方法,通过封装变化提高系统扩展性的设计模式
用于性能优化,节省内存开销,减少对象建立
目标:将对象的属性划分为内部状态与外部状态,尽量减少共享对象的数量
剥离外部状态,并把外部状态保存在其他地方,在合适的时刻 再把外部状态组装进共享对象
把握好内部状态和外部状态来避免多次建立对象。
共享是重点,用时间来换空间
使多个对象都能处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
Function.prototype.after = function(fn) { var self = this; return function() { console.log(self) console.log(fn) var ret = self.apply(this, arguments); if (ret === 'nextSuccessor') { return fn.apply(this, arguments); } return ret; } } function func1() { console.log('1'); return 'nextSuccessor'; } function func2() { console.log('2'); return 'nextSuccessor'; } function func3() { console.log('3'); return 'nextSuccessor'; } function func4() { console.log('3') } func1.after(func2).after(func3).after(func4)();
解除对象与对象之间的紧耦合关系
function Player(name, teamColor) { this.name = name; this.teamColor = teamColor; this.state = 'alive'; } Player.prototype.die = function() { playerDirector.receiveMessage('playerDead', this); } var playerDirector = { receiveMessage: function(name, player) { console.log(player.name + ' ' + name); } } var player1 = new Player('bob', 'red'); player1.die();
在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责
function Plane() { } Plane.prototype.fire = function() { console.log('发射子弹'); } function MisslePlane(plane) { this.plane = plane; } MisslePlane.prototype.fire = function() { this.plane.fire(); console.log('发射导弹') } function AtomPlane(plane) { this.plane = plane; } AtomPlane.prototype.fire = function() { this.plane.fire(); console.log('发射原子弹'); } var plane = new Plane(); plane = new MisslePlane(plane); plane = new AtomPlane(plane); plane.fire();
问题:
Function.prototype.before = function(beforeFn) { var self = this; return function() { beforeFn.apply(self, arguments); return self.apply(self, arguments); } } Function.prototype.after = function(afterFn) { var self = this; return function() { var ret = self.apply(self, arguments); afterFn.apply(self, arguments); return ret; } } function one() { console.log('one'); } function two() { console.log('two'); } function three() { console.log('three'); } two.before(one).after(three)();
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
function Light() { this.offLight = new OffLight(this); this.weakLight = new WeakLight(this); this.strongLight = new StrongLight(this); } Light.prototype.init = function() { var button = document.createElement('button'); button.innerHTML = 'press'; var self = this; this.curLight = this.offLight; button.onClick = function() { self.curLight.buttonWasPressed(); } document.body.appendChild(button); } Light.prototype.setState = function(light) { this.curLight = light; } function OffLight(light) { this.light = light; } OffLight.prototype.buttonWasPressed = function() { console.log('弱光'); this.light.setState(this.light.weakLight); } function WeakLight(light) { this.light = light; } WeakLight.prototype.buttonWasPressed = function() { console.log('强光'); this.light.setState(this.light.strongLight); } function StrongLight(light) { this.light = light; } StrongLight.prototype.buttonWasPressed = function() { console.log('无光'); this.light.setState(this.light.offLight); }
优点:
为一组子系统提供一个简单便利的访问入口。
隔离客户与复杂子系统之间的联系,客户不用去了解子系统的细节。
单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、合成复用原则和最少知识原则。
如果两个职责是同时变化的,那就不必分离
优点:降低单个类或者对象的复杂度,按照职责把对象分解成更小的粒度,这有助于代码的复用,也有利于进行单元测试。
缺点:增加了对象间联系的复杂度
体现:代理模式、迭代器模式、单例模式、装饰者模式
是一个软件实体应当尽可能少地与其他实体发生相互作用
减少对象之间的联系
体现:中介者模式、外观模式
软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。
体现:发布-订阅模式、模板方法模式、策略模式、代理模式
接口是对象能响应的请求的集合。
通过主动暴露的接口来通信,可以隐 藏软件系统内部的工作细节
语言提供的关键字
面向接口编程
抽象类的作用:
The text was updated successfully, but these errors were encountered:
真正的博客,学习了
Sorry, something went wrong.
No branches or pull requests
[TOC]
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。应用:显示登录浮窗
透明的单例模式
实现一个透明的单例类,用户从这个类中创建对象的时候,可以像使用其他类一样
用代理实现单例模式
创建方式:
惰性单例
采用事件机制,来创建,但是不符合单一职责原则,如果要创建其他标签,就得重写
通用的惰性单例
策略模式
定义一系列算法,并将它们封装成策略类,算法被封装在策略类内部的方法里,使它们可以相互替换。在客户对Context发起请求时,Context总是将请求委托给这些策略对象中间的某一个计算
优化方案:
体现了多态的特性
应用:
优点:
缺点:
代理模式
当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象。
保护代理
代理B帮助代理A过滤掉一些请求
虚拟代理
把一些开销很大的对象,延迟到真正需要它的时候才去创建。
好处
缓存代理
还能用于ajax异步请求数据,比如:分页。
其它代理
迭代器模式
提供一个方法有序的访问一个聚合对象的每一个元素,又不用关心对象的内部构造
实现一个迭代器
内部迭代器
上述的each函数,就是一个内部迭代器,each函数内部已经定义好了规则
外部跌代器
显示地跌代下一个元素
跌代类数组对象和字面量对象
区分数组
倒序迭代器
迭代器提供有序访问,所以顺序是可以设定的
中止迭代器
用break来中止迭代器
发布-订阅模式
又叫观察者模式,定义了一对多的依赖关系
作用:
实现
优点
缺点
必须先订阅再发布吗?
不是的,如qq离线消息。建立一个离线存放事件的堆栈,当事件发布的时候,如果此时还没有订阅者来订阅这个事件,暂时把发布事件的动作包裹在一个函数里,这些包装函数将被存入堆栈,等到有对象来订阅时,遍历堆栈执行包装函数。
避免全局事件的命名冲突
给Event对象提供创建命名空间的功能
命令模式
命令模式中的命令指的是一个执行某些特定事情的指令
应用场景
有时候需要向某些对象发送请求,但是不知道请求的接受者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合来设计程序,是的请求发送者和请求接收者能够消除彼此之间的耦合关系。
代码实例
撤销功能
提供一个undo方法,如小球移动,每次移动记录上一次位置,这样在undo方法中就能回到上一次位置。
重做功能
提供一个队列,将每次命令入队列,重做时出队
命令队列
第一个完成再进行第二个
宏命令
一组命令的集合
组合模式
举例:宏命令对象和普通命令对象,采用深度优先遍历这些命令并execute
用途:
注意:
好处:
模板方法模式
抽象类,需要继承实现的模式,通过封装变化提高系统的扩展性。
重写方法,通过封装变化提高系统扩展性的设计模式
享元模式
用于性能优化,节省内存开销,减少对象建立
目标:将对象的属性划分为内部状态与外部状态,尽量减少共享对象的数量
剥离外部状态,并把外部状态保存在其他地方,在合适的时刻
再把外部状态组装进共享对象
关键点
把握好内部状态和外部状态来避免多次建立对象。
共享是重点,用时间来换空间
职责链模式
定义:
使多个对象都能处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
中介者模式
解除对象与对象之间的紧耦合关系
装饰者模式
在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责
问题:
状态模式
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
优缺点
优点:
缺点:
而且系统中会因此而增加不少对象。另外,由于逻辑分散在状态类中,虽然避开了不受欢迎的条件分支语句,但也造成了逻辑分散的问题,我们无法在一个地方就看出整个状态机的逻辑。
适配器模式
外观模式
为一组子系统提供一个简单便利的访问入口。
隔离客户与复杂子系统之间的联系,客户不用去了解子系统的细节。
设计原则
单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、合成复用原则和最少知识原则。
单一职责原则(SRP)
如果两个职责是同时变化的,那就不必分离
优点:降低单个类或者对象的复杂度,按照职责把对象分解成更小的粒度,这有助于代码的复用,也有利于进行单元测试。
缺点:增加了对象间联系的复杂度
体现:代理模式、迭代器模式、单例模式、装饰者模式
最小知识原则(LKP)
是一个软件实体应当尽可能少地与其他实体发生相互作用
减少对象之间的联系
体现:中介者模式、外观模式
开放封闭原则(OCP)
软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。
体现:发布-订阅模式、模板方法模式、策略模式、代理模式
接口和面向接口编程
接口是对象能响应的请求的集合。
通过主动暴露的接口来通信,可以隐
藏软件系统内部的工作细节
语言提供的关键字
面向接口编程
抽象类的作用:
代码重构
The text was updated successfully, but these errors were encountered: