设计模式
多态
同一操作用于不同的对象上面,可以产生不同的解释和结果
将“做什么”和“谁去做”分离
动态语言
//谁去做
var Duck = function(){}
Duck.prototype.sound=function(){console.log('嘎嘎嘎')}
var Dog = function(){}
Dog.prototype.sound=function(){console.log('汪汪汪')}
//使用
makeSound(new Duck()) //嘎嘎嘎
makeSound(new Dog()) //汪汪汪
静态语言
比动态语言多一步:需要手动将Duck和Dog类型设定为Animal
方法
}
//做什么
public class AnimalSound{
public void makeSound( Animal animal ){
animal.makeSound();
}
}
//谁去做(继承Animal)
public class Duck extends Animal {
public void makeSound(){System.out.println("嘎嘎嘎")};
}
public class Dog extends Animal {
public void makeSound(){SOP("汪汪汪")};
}
public class Test{
public static void main( String args[] ){
AnimalSound animalSound = new AnimalSound();
Animal duck = new Duck();
Animal dog = new Dog();
animalSound.makeSound( duck ); //嘎嘎嘎
animalSound.makeSound( dog ); //汪汪汪
}
}
单例模式
单例模式的核心是确保只有一个实例,并提供全局访问
。PS:全局变量不是单例模式
使用命名空间
方法依然是用对象字面量的方式:
//把a和b都定义在namespace里,可以减少变量和全局作用域
var namespace = {
a: function(){
alert(1)
},b:function(){
alert(2)
}
}
//动态创建命名空间
var myApp = {};
myApp.namespace=function(){
//...
}
使用闭包封装私有变量
//ajax模块
var ajax = {
get:function(){},post:function(){}
}
//dom模块
var dom = {
get:function(api,obj){},create:function(){}
}
//event模块
var event = {
add:function(){},remove:function(){}
}
return {
ajax:ajax,dom:dom,event:event,}
})()
//使用
user.ajax.get(api,obj)
惰性单例
使用:var Model = (function(){})()
职责: 需要时才创建,将创建实例对象的职责和管理单例的职责分别放置在两个方法里
//IIFE
var getSingle2 = (function(){
var result;
return function(fn){
return result || (result = fn.apply(this,arguments))
}
})()
[惰性单例实战-创建弹窗]()
单例模式与稳妥构造函数
我认为单例模式是稳妥构造函数内部创建多个对象并合并返回的一种形式,属于创建对象的一种设计模式
函数
var Person = function(name){
var o = {
name : name,sayName : function(){
console.log(name)
}
}
return o
}
var person1 = Person('Niko')
// 单例模式
var Person = (function(name){
var _name = name
var method = {
sayName : function(){
console.log(_name)
}
}
return {
_name : _name,method : method
}
})('Niko')
Person.method.sayName() //Niko</code></pre>
策略模式
定义一系列的算法
,把它们一个个封装起来,并且使它们可以互相替换
个人理解:将大片的条件分支语句
重构成一个个策略对象
实战:计算奖金、缓动动画、表单校验
代理模式
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问作用1:事件委托
事件委托是利用事件的冒泡
原理来实现的。参考链接核心代码event.target
1
- 2
- 3
- 4
- 5
...
作用2:保护代理
作用3:虚拟代理
代码的var flower = new Flower()
//放到B中,延迟创建flower对象
var B = {
receiveFlower:function(Flower){
A.listenGoodMood(function(){
var flower = new Flower()
A.receiveFlower(flower)
})
}
}
代理的意义:单一职责原则
单一职责原则:一个类(包括对象和函数),应该仅有一个引起它变化的原因。
如果一个对象承担的职责太多,等于把这些职责耦合到了一起,会造成高耦合低内聚
缓存代理
:
可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果,如计算乘积
发布-订阅模式
模式1:先订阅再发布
//使用
$.ajax( 'http:// xxx.com?login',function(data){ // 登录成功
login.trigger( 'loginSucc',data); // 发布登录成功的消息
});
//监听
login.listen( 'loginSucc',function( data ){
//callback
});
login.listen( 'loginSucc',function( data ){
//callback
});
模式2:后订阅的离线发布
命令模式
命令模式的由来,其实是回调函数
的一个面向对象的替代品
作用:将事件做成命令,可以保存在栈中,作为命令队列
,衍生出宏命令
,智能命令
,傻瓜命令
等
做重要的是可以记录过程,已达到撤销
和重做
宏命令Macro
var macroCommand = MacroCommand()
macroCommand.add(topCommand)
macroCommand.add(leftCommand)
macroCommand.add(rightCommand)
macroCommand.execute()</code></pre>
组合模式
回顾宏命令
组合宏命令
模板方法
定义一系列的动作,最后用init()设置顺序并执行
缺点:不能像java有抽象类,子类方法必须涵盖模板方法的所有step
//原型链继承模板方法
var Tea = function(){}
Tea.prototype = new Beverage()
Tea.prototype.step1 = function(){/.../}
Tea.prototype.step2 = function(){/.../}
//...缺点
var tea = new Tea()
tea.init()
钩子方法(hook)
方法
Beverage.prototype.hook = function(){
return true //默认true
}
Beverage.prototype.init = function(){
this.step1()
if(this.hook()){
this.step2()
}
}
//子类
Tea.prototype.hook = function(){
return window.confirm( '请问需要加糖吗?' );
}
享元模式
使用场景:一个程序中使用了大量的相似对象 flyWeight 苍蝇的重量
下方代码先创建了6个div,利用对象池收集后,创建A1,B2时直接使用对象池内的dom,而没有新起h1
};
for(var i = 0,toolTip ; toolTip = ary[i++];){
toolTipFactory.recover(toolTip)
}
for(var i =0,str; str = ['A1','B2'][i++]; ){
var toolTip = toolTipFactory.create2();
toolTip.innerHTML = str;
}</code></pre>
职责链模式
个人理解:组合模式和模板方法结合 - 组合模式的外部添加
和 模板方法的钩子和步骤
核心:return this.successor && this.successor.passRequest.apply( this.successor,arguments );
//使用
var step1 = new Chain(function(){
console.log('step1')
return 'nextSuccessor'
})
var step2 = new Chain(function(){
console.log('step2')
this.next()
})
var step3 = new Chain(function(){
console.log('step3')
})
step1.setNextSuccessor(step2).setNextSuccessor(step3)
step1.passRequest()
中介者模式
我认为职责链模式
是去中心化,中介者模式
就是中央集权
装饰者模式
待定
状态模式
待定
适配器模式
适配器(adapter)别名包装器(wrapper)
继续“多态”一节,缺点在于要保证不同对象都有一个相同名称的方法
适配器就是为了弥补这一缺点,由一个对象包装另一个对象
var DogAdapter function(oldDog){
let newDog = function(){}
newDog.prototype.sound = oldDog.prototype.barking
return function(){
return new newDog()
}
}
//使用
makeSound( new DogAdapter() )
装饰者模式、代理模式和外观模式都属于“包装模式”
设计原则和编程技巧
单一职责原则
- 一个对象(方法)只做一件事情
最少知识原则
- 减少对象之间的联系
封闭-开放原则
参考
- [1] JavaScript设计模式与开发实践[M]