JavaScript常用设计模式

开放封闭原则:

开放性:当有新需求时,可以对现有代码进行扩展,在不影响现有功能的前提下,来实现新需求;

封闭性:模块的源代码不能被修改,神圣不可侵犯(前提是功能是完整无误的,修复bug不算破坏封闭性原则);

内聚性/耦合性

内聚性:表示单个模块内功能性强度性的度量;若一个模块各个元素之间联系很强,那么该模块就具有高内聚,相反就是低内聚;

耦合性:表示各个模块之间联系性的度量;若各个模块联系性很强,那么各个模块的耦合性很高,相反就是低耦合;

总结:一个好的程序架构,一般遵循高内聚低耦合,这样就能对各模块进行扩展和复用,代码质量就比较高;

1.工厂/构造者/原型模式

工厂/构造者/原型模式的共同点在于实现封装性,达到程序的复用。提高开发效率;不同点在于实现的方式不一致;代码如下:

    /*
    *定义工厂模式
    *通过函数封装某功能代码,以达到复用
    */
    function testOne(){
        var obj={
            name:"工厂模式"
        };
        obj.setName=function(name){
            this.name=name;
        }
        return obj;
    }
    //执行函数
    testOne().setName("改变了");
    /*
    *定义构造者模式
    *学过Java的知道,每个类中都有构造函数,JavaScript不是面向对象语言
    *但是它也可以实现,并通过new关键字实例化
    */
    function testTwo(){
        this.name="构造者模式";
        this.setName=function(name){
            this.name=name;
        }
    }
    //执行
    var testObj=new testTwo();
    testObj.setName("改变了");
    /*
    *定义原型模式
    *通过原型链的形式实现功能的封装
    */
    function testTwo(){
        this.name="原型模式";
    }
    testTwo.prototype.setName=function(name){
        this.name=name;
    }
    //执行
    var testObj=new testTwo();
    testObj.setName("改变了");

2.单例模式:

保证一个类只有一个实例,在实例化类之前先判断该实例是否存在,如果存在直接引入,不存在就进行实例化类;在JavaScript中,单例模式类作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象;通常采用自执行匿名函数和闭包方式实现;代码如下:

/*定义单例模式*/
var single=(function(){//自执行匿名函数
    var obj=null;
    /*1.访问函数外面的变量;2.把变量保存在内存中,不让变量被回收;
    **2.特点:函数1里面套函数2,然后函数1返回函数2;
    **3.缺点:容易吃内存,性能毛病;故闭包不用就将里面的变量全部null掉
    */
    function Constructor(){ 
        //dothing~~~
    }
    return {
        testSingle:function(){
            if(obj==null){
                obj=new Constructor();
            }
            return obj;
        }
    }
})();
//执行单例模式代码
single.testSingle();

以上是单例模式的一种,具体根据需求衍生出不同的单例模式;记住单例模式的核心:一个类只能有一个实例;以上单例模式不管在什么时候都会执行一次;因为采用了自执行匿名函数。如果想在有需要的时候执行,该怎么做?
惰性单例模式

    var signle=function(funs){
        var obj=null;
        return function(){
                return obj || (obj=funs.apply(this,arguments));
            }
    }

3.代理模式

“代理”生产商和消费者之间有个代理商,用来联系生产商和消费者的联系,进行商品交易。代理商要有生产商所提供的的信息展示给消费者(程序中称为接口);

  1. 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
  2. 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

代理模式的一个好处就是对外部提供统一的接口方法,而代理类在接口中实现对真实类的附加操作行为,从而可以在不影响外部调用情况下,进行系统扩展。也就是说,我要修改真实角色的操作的时候,尽量不要修改他,而是在外部在“包”一层进行附加行为,即代理类。

    var factory_obj={//定义真实对象
        name:"test",
        address:"中国北京",
        setName:function(name){
            this.name=name;
        },
        showName:function(){
            return this.name
        },
        setAddress:function(addr){
            this.address=addr;
        },
        showAddress:function(){
            return this.address;
        }
    };
    var agent_obj={//定义代理对象
        setName:function(name){
            factory_obj.setName(name);
        },
        showName:function(){
            return factory_obj.name;
        },
        setAddress:function(addr){
            factory_obj.setAddress(addr);
        },
        showAddress:function(){
            return factory_obj.address;
        }
    }
    //定义使用者
    //通过调用代理对象agent_obj来执行factory_obj对象
    agent_obj.setName("我是消费者1");
    console.log(agent_obj.showName());
    agent_obj.setAddress("江西上饶");
    console.log(agent_obj.address);

总结:在代理模式中一定要同时具备真实对象和代理对象,真实对象是实际需要操作的对象,代理对象是一个能访问到真实对象的接口。他们相互依赖;

优点:可以在不影响真实对象的基础上进行其他功能扩展;保持真实对象的完整性,符合开放封闭原则;在以上代码进行功能扩展:

    //扩展age属性,并定义setAge和showAge方法
    agent_obj['age']="16";
    agent_obj['setAge']=function(age){
        this.age=age;
    }
    age_obj['showAge']=function(){
        return this.age;
    }

4.发布/订阅者模式

发布/订阅者模式主要是为了松散耦合,提高代码质量;它大致拥有“发布者”和“订阅者”这两个角色;订阅者关注了某发布者后,当发布者发布最新状态,则订阅就会收到通知,并作出相应的动作;

场景实例:现在文章类APP都有对文章作者进行关注的功能,关注之后,当文章作者发布新文章时,系统就会通知你文章更新了。

    (function(){
        var manageObj={}; //注册管理中心
        var Publish=function(){//注册发布者
            
        }
        var Subscribe=function(){//注册订阅者
            return this;
        }
        /**
        * 注册订阅事件
        * @param type:string 订阅的标识
        * @param funs:function 订阅标识的回调函数
        **/
        Subscribe.prototype.add=function(type,funs){
            if(typeof type == "string"){
                manageObj[type]=funs;
            }else{
                console.error("add(type:string,funs:function)参数类型Error");
            }
        }
        /**
        * 取消订阅事件
        * @param type:string 订阅的标识
        **/
        Subscribe.prototype.remove=function(type){
            if(typeof type == "string"){
                var keys=Object.keys(manageObj);
                for(var i=0;i=keys.length;i++){
                    if(keys[i] == type){
                        delete manageObj[types];
                        break;
                    }
                }
            }else{
                console.error("remove(type:string)参数类型Error");
            }
        }
        /**
        * 触发订阅事件
        * @param type:string 订阅的标识
        **/
        Subscribe.prototype.trigger=function(type){
            if(typeof type == "string"){
                if(typeof manageObj[type] == "undefined"){
                    console.error(type+"没有订阅事件");
                }else{
                    manageObj[type]();
                }
            }else{
                console.error("trigger(type:string)参数类型Error");
            }
        }
        //实例化Subscribe
        var subObj=new Subscribe();
        subObj.add("definedEvent",function(){
            console.log("我是自定义事件");
        });
        subObj.trigger("definedEvent");
    })();
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容