设计模式

一、类继承它描绘了被创建对象的属性及特征。使用new关键字调用构造函数可以创建类的实例
基于原型的面向对象设计方法总共有三种
1、拼接继承: 是直接从一个对象拷贝属性到另一个对象的模式。被拷贝的原型通常被称为mixins。ES6为这个模式提供了一个方便的工具Object.assign()。在ES6之前,一般使用Underscore/Lodash提供的.extend(),或者 jQuery 中的$.extend(), 来实现。
2、原型代理:JavaScript中,一个对象可能包含一个指向原型的引用,该原型被称为代理。如果某个属性不存在于当前对象中,就会查找其代理原型。代理原型本身也会有自己的代理原型。这样就形成了一条原型链,沿着代理链向上查找,直到找到该属性,或者找到根代理Object.prototype为止。原型就是这样,通过使用new关键字来创建实例以及Constructor.prototype前后勾连成一条继承链。当然,也可以使用Object.create()来达到同样的目的,或者把它和拼接继承混用,从而可以把多个原型精简为单一代理,也可以做到在对象实例创建后继续扩展。
3、函数继承:在JavaScript中,任何函数都可以用来创建对象。如果一个函数既不是构造函数,也不是 class,它就被称为工厂函数。函数继承的工作原理是:由工厂函数创建对象,并向该对象直接添加属性,借此来扩展对象(使用拼接继承)。
类式继承: 
//声明父类
function SuperClass(){
    this.superValue = true;
}
//为父类添加共有方法
SuperClass.prototype.getSuperValue = function(){
    return this.superValue;
}
//声明子类
SubClass.prototype = new SuperClass();
//为子类添加共有方法
SubClass.prototype.getSubClassValue = function(){
    return this.subValue;
}

构造函数式继承 
//声明父类
function SuperClass(id){
    this.books = ['js','css','html'];
    this.id = id;
}
//父类声明原型方法
SuperClass.prototype.showBooks = function(){
    console.log(this.books);
}
//声明子类
function SubClass(id){
    //继承父类
    SuperClass.apply(this,id);
}

多继承 
var extend = function(target, source){
    for(var prototype in source){
        target[prototype] = source[prototype];
    }
    return target;
}
call,apply作用一样,只是参数形式不同。
1)指定this指向 func.call(this)
2)Function.prototype.bind大部分浏览器支持,指定内部指向。 
//简化版
Function.prototype.bind = function(context){
    var self = this; //保持原函数
    return function(){ //返回新函数
        return self.apply(context,arguments); //执行新函数,把之前传入的context作为新函数的this
    }
}
var obj = {this.name = 'seven'}
var func = function(){
    console.log(this.name);
}.bind(obj);
func();//输出seven
//借用构造函数
var A = function(name){
    this.name = name;
};
var B = function(){
    A.apply(this,arguments);
};
B.prototype.getName = function(){
    return this.name;
};
var b = new B('seven');
console.log(b.getName()) //输出seven

二、模式是经过了大量实际项目经验的优秀解决方案,javascript的函数既可以作为普通函数被调用,也可以作为构造器使用。 

1、单例模式:保证一个类只有一个实例
var singleton = function(name){
    this.name = name;
};

singleton.prototype.getName = function(){
    console.log(this.name);
}

singleton.getInstance = (function(){
    var instance = null;
    return function(name){
        if(!instance){
            instance = new singleton(name);
        }
        return instance;
    }
})();

使用闭包封装私有变量 
var user = (function(){
    var _name = 'seven',
        _age = 25;
    return {
        getUserInfo: function(){
            return _name + '_' + _age;
        }
    }
})();

单例逻辑抽离 
var getSingle = function(fn){
    var result;
    return function(){
        return result || (result = fn.apply(this,arguments));
    }
}

2、策略模式:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。适合类似表单验证等情况,减少if-else 
var strategies = {
    'S': function(salary){
        return salary * 4;
    },
    'A': function(salary){
        return salary * 3;
    },
    'B': function(salary){
        return salary * 2;
    }
};

3、代理模式:为对象提供一个代用品或占位符,以便控制它的访问 
图片懒加载: 
var myImage = (function(){
    var imgNode = document.creatElement('img');
    document.body.appendChild(imgNode);

    return {
        setSrc : function(src){
            imgNode.src = src;
        }
    }
})()
var proxyImage = (function(){
    var img = new Image;
    img.onload = function(){
        myImage.setSrc(this.src);
    }
    return {
        setSrc: function(src){
            myImage.setSrc('file://loading.gif');
            img.src = src;
        }
    }
})();
proxyImage.setSrc('http://pic.png');

计算乘积 
var mult = function(){
    var a = 1;
    for(var i = 0, l = arguments.length; i < l; i++){
        a = a * arguments[i];
    }
    return a;
};
var plus = function(){
    var a = 1;
    for(var i = 0, l = arguments.length; i < l; i++){
        a = a + arguments[i];
    }
    return a;
};

创建缓存代理的工厂 
var createProxyFactory = function(fn){
    var cache = {};
    return function(){
        var args = Array.prototype.join.call(arguments,',');
        if(args in cache){
            return cache[args]; //缓存计算结果
        }
        return cache[args] = fn.apply(this,arguments);
    }
};

var proxyMult = createProxyFactory(mult),
    proxyPlus = createProxyFactory(plus);

    console.log(proxyMult(1,2,3,4)); //24
    console.log(proxyMult(1,2,3,4)); //24
    console.log(proxyPlus(1,2,3,4)); //10
    console.log(proxyPlus(1,2,3,4)); //10

4、迭代器模式:提供一种方法可以顺序访问一个聚合对象中各个元素,而不需要暴露该对象的内部表示
5、发布-订阅模式(观察者模式):一种一对多的关系,当一个对象状态发生改变时,所有依赖它的对象都将得到通知
缺点:模块间使用太多发布-订阅模式通信,模块与模块之间的联系被隐藏到背后,会搞不清消息来自哪个模块,或者消息流向哪个模块。给维护带来麻烦。同时消息订阅后但最后都未发生,订阅者会始终存在于内存中 
 
6、命令模式:执行某些特定事情的指令 
7、模版方法模式:基于继承的设计模式 
8、享原模式:用于性能优化的模式,用共享技术有效支持大量细粒度的对象 
9、职责链模式:将对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理完它为止。
优:解耦请求发送者何N个接收者之间的关系。
缺:某次请求中大部分节点都没有起到实质作用,从性能考虑尽量避免过长职责链。 
 
10、中介者模式:解除紧耦和关系,增加一个中介者对象,当一个对象改变时只需要通知中介者对象即可。
缺点:系统增加中介者对象,使复杂度转移到了中介者对象中。 
 
11、装饰者模式:动态的给某个对象添加一些额外的职责,而不会影响从这个类中派生的其它对象
继承:父类子类耦合性强,且父类对子类可见,破坏了封装性。 
12、状态模式 
 
 
 
 
 
 
 
posted @ 2017-05-04 22:17  圣耀  阅读(190)  评论(0编辑  收藏  举报