设计模式总结
1.单例模式
场景就是比如前端常用的,点击弹出遮盖层。下面的这个代码可能是平常会去写的。
var mask = document.body.appendChild(document.createElement( ''div' ) );
$( ''button' ).click( function(){
mask.show();
} )
但是也有一点不够好,也许一直没有人点击弹出遮盖层。这样的话我们就白白浪费了一个div,寸土寸金。下面这个使用了单例模式,而且很巧妙的使用了闭包,又避免了mask成为全局变量污染。
var createMask = function(){
var mask;
return function(){
return mask || ( mask = document.body.appendChild( document.createElement('div') ) )
}
}()
不过这还不够,我们肯定期待可以写一个类似于工厂的东西,不管来了什么函数都可以包装成单例模式。
var singleton = function( fn ){
var result;
return function(){
return result || ( result = fn .apply( this, arguments ) );
}
}
var createMask = singleton( function(){
return document.body.appendChild( document.createElement('div') );
})
2.简单工厂模式
这个概念其实最常见。而我们每天都会使用工厂模式,最最常见的就是新建对象的new方法。就像工厂一样,你把一个对象传进来,然后函数返回你想要的东西。
function A( name ){
this.name = name;
}
function ObjectFactory(){
var obj = {},
Constructor = Array.prototype.shift.call( arguments );
obj.__proto__ = typeof Constructor .prototype === 'number' ? Object.prototype
: Constructor .prototype;
var ret = Constructor.apply( obj, arguments );
return typeof ret === 'object' ? ret : obj;
}
var a = ObjectFactory( A, 'kopchen' );
alert ( a.name );
下午看了三次这个代码,这段代码值得多看几次。
3.观察者模式(发布-订阅模式)
这个觉得是最最常见的设计模式,文章只讲了使用,恰好构造观察者模式的方法我原来看过,下面是我写的代码。
var observer = {};
//对于订阅者
observer['event1'] = [];
ovserver['event1'].push(callback1);
//对于发布者,当他想要触发某一事件(event)
observer['event'].forEach((ele)=>{
ele();
})
H5定位组件里特意用一个文件写过这个方法。订阅者把他们订阅的事件当成一个对象的key,所有相同的事件的回调函数保存在一个数组里。当发布者触发这一个事件的时候会把这事件对应的所有回调函数挨个触发。
4.配适器模式
比喻很形象,比如你现在正在用一个自定义的js库. 里面有个根据id获取节点的方法id(). 有天你觉得jquery里的实现得更酷, 但你又不想让你的工程师去学习新的库和语法. 那一个适配器就能让你完成这件事情.
$id = function( id ){
return jQuery( '#' + id )[0];
}
//或者转换数据结构也可以
my.category = adapterCategory ( afu.category );
5.代理模式
每次收到事件都要响应明显是耗资源且不必要的。可以利用代理模式负责收集事件,然后处理放在代理函数之后。
var keyMgr = keyManage();
keyMgr.listen( ''change', proxy( function( keyCode ){
console.log( keyCode );
)} );
6.外观模式
因为我们要保持合理的粒度。所以在更靠近用户的层面封装更高层的接口,方便客户端或者用户使用更加方便。
var stopEvent = function( e ){ //同时阻止事件默认行为和冒泡
e.stopPropagation();
e.preventDefault();
}
7.策略模式
策略模式就是把一个个方法封装起来。比如表单验证,非空敏感词字符过长等,把方法一个个封装起来比if else的可维护性要好很多。
nameInput.addValidata({
notNull: true,
dirtyWords: true,
maxLength: 30
})
而notNull,maxLength等方法只需要统一的返回true或者false,来表示是否通过了验证。
validataList = {
notNull: function( value ){
return value !== '';
},
maxLength: function( value, maxLen ){
return value.length() > maxLen;
}
}
8.模版方法模式
这个很有意思,其实可以理解成比如一个架构师,预先搭好整个的骨架,然后剩下的血肉再让大家分一分去实现就好了。
var gameCenter = function(){
}
gameCenter.ptototype.init = function(){
this.login();
this.gameStart();
this.end();
}
gameCenter.prototype.login= function(){
//do something
}
gameCenter.prototype.gameStart= function(){
//空函数, 留给子类去重写
}
gameCenter.prototype.end= function(){
alert ( "欢迎下次再来玩" );
}
比如上边这种,游戏的大流程都是一定的,可以先把大的框架搭出来。其他人继承父类就好了。有必要的话可以把父类写成protected。
9.中介者模式
代码中的mvc不就是么。中介者负责传递消息,另外两端考虑的东西就可以相对简单。
var mode1 = Mode.create(), mode2 = Mode.create();
var view1 = View.create(), view2 = View.create();
var controler1 = Controler.create( mode1, view1, function(){
view1.el.find( ''div' ).bind( ''click', function(){
this.innerHTML = mode1.find( 'data' );
} )
})
var controler2 = Controler.create( mode2 view2, function(){
view1.el.find( ''div' ).bind( ''click', function(){
this.innerHTML = mode2.find( 'data' );
} )
})
10.组合模式
用户只需要操作最上层的接口,就可以对所有成员做相同的操作。
form.validata = function(){
forEach( fields, function( index, field ){
if ( field.validata() === false ){
return false;
}
})
return true;
}
11.备忘录模式
对数据进行缓存
var Page = function(){
var page = 1,
cache = {},
data;
return function( page ){
if ( cache[ page ] ){
data = cache[ page ];
render( data );
}else{
Ajax.send( 'cgi.xx.com/xxx', function( data ){
cache[ page ] = data;
render( data );
})
}
}
}()