zoukankan      html  css  js  c++  java
  • javascript设计模式小记

    一、单体模式
    用于保存一组属性或方法(简单的可以是一个对象字面量),如果可实例化,只能被实例化1次(即return)。

    (function(){
    ...
    return {
    ....
    }
    })()

    可用来划分划分命名空间,封装私有属性和方法(return出来的是公用接口);可实现惰性加载(再一步封装,在使用时才实例化);还可以实现分支技术。

    二、工厂模式
    在一个方法中,需要用到几个类的实例,而这些类都实现了相同的接口(可能派生自一个类),所以可以互换使用。把创建这些类的实例的代码单拿出来放在一个地方(可以是一个单体或一个新建的类中等),这个地方就是工厂。
    工厂可以弱化对象之间的耦合,增强代码的重用性,统一在一个地方,方便维护和管理。

    三、桥接模式
    将抽象和其实现分离,利于模块坏和单元测试。
    比如用在事件监听的回调函数中。

    el.addEventListener('click', 'fnA', 'false');
    function fnA(){
    var id = this.id;
    ....
    }

    这种情况fnA与el耦合,方法不能进行单元测试,改用桥接模式:

    function fnB(id){
    ...
    }
    el.addEventListener('click', 'fnQqiao', 'false');
    fnQqiao(){
    fnB(this.id);
    }

    大概这个意思,fnB可以进行单元测试,也可以用在其他地方。

    四、组合模式

    自由组合,每个叶对象和组合对象都实现了相同的接口,可以互换使用。
    只需对顶层操作,所有叶对象都执行方法(组合类中用一个数据结构储存子对象,遍历操作)。如果树的结构庞大,不宜使用。

    五、门面模式
    简化接口,方便使用。常用到的addEvent,createXHR等方法,还有jq,YUI等JS库都属于门面模式。

    六、适配器模式
    现有有的接口不能满足要求,又不想完全重写浪费时间,中间加个包装器。

    function fnA(str1, str2,str3){
    //原方法支持3个字符串参数
    }

    现有的数据是对象字面量形式的:

    var a = {
    str1 : '111',
    str2 : '222',
    str3 : '333'
    }

    要把对象a传到fnA中就需要用到适配器:

    function fnB(o){
    fnA(o.str1, o.str2, o.str3);
    }

    七、装饰者模式
    为现有的对象添加新的特性,如果通过添加子类不容易实现(特性有多种组合,需创建大量子类),可使用装饰者模式。装饰者生成的对象和原来的对象使用相同接口,可以直接代替原对象使用。

    var jiekou = new Interface('jiekou',['fanA','fanB']);//实现了2个方法的接口
    function ClassA(){}
    ClassA.prototype = {
    fnA : function(){},
    fnB : funciton(){}
    }

    创建装饰者:

    function ClassB(obj){
    Interface.ensureImplements(obj, jiekou);
    this.obj = obj
    }
    ClassB.prototype = {
    fnA : function(){
    return this.obj.fnA()+10;
    },
    funB : function(){
    return this.obj.fnB()+5;
    }
    }
    var a = new ClassA();
    a = new ClassB(a);

    ClassB就是ClassA的装饰者,最后创建的a对象和原a对象方法都是等同的,但值改变了。

    八、享元模式
    如果一个类会创建很多实例,并且有些数据(this.a,this.b,this.c等)在实例是一样的,其他一些数据(this.d,this.e)在实例中存在差异化,可以把d和e这样的数据拿出来直接传到方法中去,而a,b,c这样的数据是共享的。
    然后用一个工厂来创建对象,判断如果对象创建过了,就直接返回对象;否则创建新对象。这样会大大提高内存和CPU使用率。

    function ClassA(text){
    this.text = text;
    this.element = document.createElement('div');
    }
    ClassA.prototype.set = function(){
    this.element.innerHTML = this.text;
    }
    var a = new ClassA('111');
    a.set();
    console.log(a.element.innerHTML);

    假设页面需要大量的ClassA的对象,就会创建大量div。下面改成享元模式:

    var A = (function(){
    function ClassA(){
    this.element = document.createElement('div');
    }
    ClassA.prototype.set = function(text){
    this.element.innerHTML = text;
    }
    var objA = null;
    return{
    createA : function(text){
    if(objA == null){
    objA = new ClassA();
    }
    objA.set(text);
    return objA;
    }
    }
    })();
    var a = A.createA('111');
    console.log(a.element.innerHTML);

    大概是这个意思,这样不管创建多少对象,就创建了一个DIV。

    九、代理模式--虚拟代理
    用代理对象代替原来对象进行访问,它们都实现了相同的借口。创建代理对象的实例其实还是间接的创建了原对象,并不是像装饰者那样创建了新的类。
    目的是把本体的实例化推迟到真正需要的时候(适合实例化本体比较费时和本体尺寸较大)。也就是说创建一个代理实例,当执行实例方法的时候才真正创建本体的实例。

    function ClassA(a){
    this.a = a;
    }
    ClassA.prototype = {
    fnA : function(){},
    fnB : fucntion(){},
    ...
    }
    var a = ClassA('1');//这样会马上实例化ClassA

    下面使用代理模式:

    function ClassAProxy(a){
    this.a = a;
    this.obj = null;
    }
    ClassAProxy.prototype = {
    _init : function(){
    if(this.obj == null){
    this.obj = new ClassA(this.a);
    }
    },
    fnA : function(){
    this._init();
    return this.obj.fnA();
    },
    fnB : function(){
    this._init();
    return this.obj.fnB();
    }
    }
    var a = ClassAProxy('1');//这里并没有实例化ClassA
    a.fnA();//当调用方法时候才实例化ClassA。

    十、观察者模式
    把人行为和应用程序的行为分开。事件监听器(addEventListener)就是一个内置观察者。你可以这样,点击一次执行2个事件:

    el.addEventListener('click', fnA, false);
    el.addEventListener('click', fnB, false);

    但却不能这样:

    el.onclick = fnA();
    el.onclick = fnB();

    十一、命令模式
    所有命令对象都执行一个操作(execute),用途就是调用命令对象所绑定的操作(action)。
    就是element不和action直接绑定,element执行的是execute,execute在去调用action。而action是灵活的。

    var Command = function(action){//命令类
    this.action = action;
    }
    Command.prototype.execute = function(){
    this.action();
    }
    var jiekou = new Interface('jiekou',['execute ']);//创建接口
    function ClassMethod(name){//方法类
    this.name = name;
    }
    ClassMethod.prototype = {
    consoleMethod : function(){
    console.log(this.name);
    },
    alertMethod : function(){
    alert(this.name);
    }
    }
    function fn(command){//执行的地方
    Interface.ensureImplements(command, jiekou);
    command.execute;
    }
    var a = new ClassMethod('11');
    var consoleCommand = new Command (a.consoleMethod);//创建2个命令
    var alertCommand = new Command (a.alertMethod);
    fn(consoleCommand);//执行命令
    fn(alertCommand);

    十二、职责连模式
    假如要添加一个对象,要判断对象属于哪个类(假如有5个类),可能生成5个实例来判断。创建一个职责链,每一个接受者对请求分析,要么处理它,要么往下传。

  • 相关阅读:
    flask简单应用以及配置文件的写法。
    Django REST framework使用及源码分析之节流
    rancher1.6高可用集群搭建
    Rancher安装多节点高可用(HA)
    Rancher 2.2.2
    TeamCity+Rancher+Docker实现.Net Core项目DevOps(目前成本最小的DevOps实践)
    Docker学习笔记_10 docker应用
    一键获取数据库整体信息脚本
    MySQL性能优化最佳实践
    MySQL性能优化最佳实践
  • 原文地址:https://www.cnblogs.com/bianyuan/p/2356666.html
Copyright © 2011-2022 走看看