blogs icon indicating copy to clipboard operation
blogs copied to clipboard

常见的几种设计模式

Open forever-z-133 opened this issue 7 years ago • 0 comments

单例模式

singleton,产生一个类的唯一实例。 可以减少全局变量,且保证该实例的唯一性。 但会有闭包的毛病(占用内存),再者想创建另一个相似实例有悖于此模式。

var singleton = function( fn ){
    var result;
    return function(){
        return result || ( result = fn .apply( this, arguments ) );
    }
}
// 伪代码,不管运行几次 createGame,都只有一个 Game 实例
var createGame = singleton(function() {
    return new Game();
})
// 或者这样,只会新建一个元素
var num = 0;
var createMask = singleton(function(){
    var $d = document.createElement('div');
    $d.className = 'x' + ++num;
    return document.body.appendChild($d);
});
var mask1 = createMask();
var mask2 = createMask();
console.log(mask1, mask2); // <div class="x1"></div> <div class="x1"></div>

观察者模式

即 on 绑定回调,trigger 触发回调

var Events = function() { 
    var listen, log, obj, one, remove, trigger, __this;
    var obj = {}, __this = this;
    listen = function( key, eventfn ) {
        var stack, _ref;
        stack = ( _ref = obj[key] ) != null ? _ref : obj[ key ] = [];
        return stack.push( eventfn );
    };
    one = function( key, eventfn ) {
        remove( key );
        return listen( key, eventfn );
    };
    remove = function( key ) {
        var _ref;
        return ( _ref = obj[key] ) != null ? _ref.length = 0 : void 0;
    };
    trigger = function() {  //面试官打电话通知面试者
        var fn, stack, _i, _len, _ref, key;
        key = Array.prototype.shift.call( arguments );
        stack = ( _ref = obj[ key ] ) != null ? _ref : obj[ key ] = [];
        for ( _i = 0, _len = stack.length; _i < _len; _i++ ) {
            fn = stack[ _i ];
            if ( fn.apply( __this,  arguments ) === false)
            return false;
        }
    }

    return {
        on: listen,
        one: one,
        remove: remove,
        trigger: trigger
    }
}
// 例子
var eee = new Events;
eee.on('end', function(){ console.log('2s 后') });
setTimeout(function(){ eee.trigger('end'); }, 2000);

适配器模式

adapter,类似于USB转接口,也就是中间加一个过程,让参数得以匹配

// 例子1:改变函数参数传递
var something = { x: 1, y: 2, z: 3 };
var myfun = function(a, b, c) {
    console.log(a, b, c);
}
var _myfun = function(obj) { // 这就是适配器
    obj.x = Math.max(0, Math.min(obj.x, 5));
    myfun(obj.x, obj.y, obj.z);
}
console.log(_myfun(something));

代理模式

proxy,把对一个对象的访问, 交给另一个代理对象来操作。 比如进行允许/拒绝/缓存/合并等操作。

// 例子
var plus = function () {
    var args = [].slice.call(arguments, 0);
    return args.reduce((x, y) => x + y);
}
var proxy = function (fn) {
    var cache = {};
    return function(){
        var args = Array.prototype.join.call(arguments, "-");
        if( args in cache ){ // 判断是否被计算过
            console.log( "从缓存中拿取" );
            return cache[args];
        }
        return cache[args] = fn.apply(null, arguments);
    }
}
var add = proxy(plus);
console.log(add(1, 2, 3, 4)); // 10
console.log(add(1, 2, 3, 4)); // 从缓存中拿取 10
// 

包装/装饰者模式

decorator,为对象动态加入行为,都是不改变原来的对象添加功能。 包装模式与代理模式的不同,在于代理模式返回的结果会不变,包装模式则可能不会。


委托模式

delegater,接收多个对象,将请求委托给另一个对象统一处理请求。

// 比如,事件冒泡和事件委托
function clicked() {}
var $li = document.querySelecterAll('li');
for (var i=0,len=$li.length; i<len; i++) {
  $li.onclick = clicked
}
var $ul = document.querySelecterAll('ul');
$ul.onclick = function(e){
  var el = e.target;
  if (el.tagName.toLowerCase() == 'li') {
    clicked.call(el, e)
  }
}

forever-z-133 avatar Jan 03 '18 03:01 forever-z-133