JavaScript

JavaScript - 设计模式 - 命名空间

2017-03-29  本文已影响54人  西巴撸

本小节主要讲解三种常用的设计模式和命名空间,第一种是工厂模式,第二种是单利模式,第三种是观察者模式


设计模式概述

是为了解决在开发中可能遇到的需求(相似),而提出的一套解决方法.

设计模式要求:

工厂模式

批量创建大量的同类型的对象

优点 :

核心过程 :

1.需要接收传入的参数(要生产的产品的类型)
2.判断 是否支持生产
3.设置子构造函数的原型对象
4.把新创建的对象返回

<script>
    //1. 提供一个父构造函数
    function PhoneMake(){};
    //2. 设置这个父构造函数的原型对象(属性|方法)
    PhoneMake.prototype.logDes = function(){
        console.log("我们的口号是:" + this.des);
    }

    //3. 在父构造函数身上添加静态工厂方法
    PhoneMake.factory = function(typeStr){
        // 3.1 需要接收传入的参数(要生产的产品的类型)
        var productType =  typeStr;

        //var Dog = PhoneMake[productType];
        //3.2 判断 是否支持生产
        if (typeof PhoneMake[productType]  != "function")
        {
            //抛出一个异常
            throw "对不起,我们工厂和这个品牌没有商务合作,不能生产!"
        }

        //3.3 设置子构造函数的原型对象
         //为了获得构造函数原型对象的方法
        PhoneMake[productType].prototype = new PhoneMake(); 

        //3.4 设置子构造函数的原型对象
       var newProduct = new PhoneMake[productType]();

        //3.5 把新创建的对象返回
        return newProduct;
    }

    //4. 定制合作伙伴
    PhoneMake.iphone = function(){
        this.des = "最安全最稳定的系统,最垃圾的体验"
    }
    PhoneMake.oppo = function(){
        this.des = "充电两小时,通话五分钟"
    }
    PhoneMake.vivo = function(){
        this.des = "照亮你的美,你本来就很美"
    }
    PhoneMake.meizu = function(){
        this.des = "我就是我,不一样的魅族"
    }

    //5. 直接使用父构造函数的静态工厂方法来创建指定的产品对象
    var iphone = PhoneMake.factory("iphone");
    var vivo = PhoneMake.factory("vivo");
    var oppo = PhoneMake.factory("oppo");
    var meizu = PhoneMake.factory("meizu");
    var xiaomi = PhoneMake.factory("xiaomi");

    iphone.logDes();
    vivo.logDes();
    oppo.logDes();
    meizu.logDes();

</script>

单利模式

在整个程序的运行过程中,一个类只有一个实例对象

js中的单利模式

1.字面量
2.内置构造函数(Array Date Function Object)
3.工厂函数
4.自定义构造函数(单利模式)

1.弱类型,脚本,轻量级,面向对象,基于原型(对象),解释行语言.函数式.
2.js到底是不是一门面向对象(类)的语言?
3.js是一门支持面向对象的语言.(封装|继承|多态)

单利模式实现之后的表现

var p1 = new 构造函数()
var p2 = new 构造函数()
p1 == p2

<script>
    function Person(){
        //首先创建一个空的对象
        //默认把新的对象赋值给this
        //把新对象返回
    }
    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);
</script>

单利模式的实现方式01 ----> 全局变量

全局变量来保存对象实现单利模式

存在的问题

<script>
    var instance;
    function Person(){
        if(instance)
        {
            console.log("对象已经被创建,直接把之前创建好的对象返回");
            return instance;
        }
        instance = this;
        this.name = "奥特曼";
        this.age = 1000;
        console.log("第一次创建对象,创建对象之后并返回");
    }

    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);
    var p3 = new Person();

    instance = "demo";
    var p4 = new Person();
    console.log(p4);
    console.log(p4 == p1);
</script>

单利模式的实现方式02 ----> 静态属性

静态成员:直接添加到构造函数身上的属性或者是方法

存在的问题

<script>
    function Person(){
        //判断对象是否已经被创建
        if (Person.instance)
        {
            console.log("之前已经创建过对象,直接返回");
            return Person.instance;
        }

        this.name = "大黄蜂"
        Person.instance  = this;
        console.log("第一次创建");
    }

    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);


    instance = "demo";
    var p3 = new Person();
    console.log(p1 == p3);

    Person.instance = "123";
    var p4 = new Person();
    console.log(p4 == p1);
</script>

单利模式的实现方式03 ----> 惰性函数

核心过程

<script>
    // 01 提供一个构造函数
    function Person(){
        //this01
        //02 在构造函数内部声明一个私有的变量
        var instance;
        //03 使用惰性函数定义更新构造函数的实现(直接把instance返回)
        Person = function(){
            //内部默认会创建一个空的对象 this02
            return instance;
        }
        //04 设置原型对象[新构造函数的原型对象 = 旧构造函数的原型对象]
        //原型链继承:Man.prototype = new Person();
        //原型式继承:Man.prototype = Person.prototype;
        //Person.prototype = this.__proto__;  //非标准(代码中不要出现)
        Person.prototype = this;

        //05 使用新的构造函数创建实例对象,并且赋值给instance
        instance = new Person();
        //instance = this;
        //06 修正对象的构造函数指向
        instance.constructor = Person;
        // 07 通过instance设置实例属性和方法
        instance.name = "我很好听";
        // 08 把instance返回
        return instance;
    }

    Person.prototype.des = "描述信息";
    var p1 = new Person();
    Person.prototype.hi = "hi";

    var p2 = new Person();
    console.log(p1 == p2);

    console.log(p1.constructor == Person);  //true
    console.log(p1.des);
    console.log(p1.hi);
</script>

单利模式的实现方式04 ----> 全局变量 + 即时函数

<script>
    var Person;
    (function(){
        var instance;

        Person = function (){
            if(instance)
            {
                return instance;
            }
            this.name = "momo";
            instance = this;
        }
    })();

    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);
</script>

观察者模式

观察者模式举例说明

女神:rose(发布者)
男生:jack(订阅者)
男生:tom(订阅者)

创建或者是设置一个发布者
创建订阅者对象
注册订阅者
测试(发状态)

<script>
    //01 创建或者是设置一个发布者
    var rose = {
        user:[],
        addUser:function(fn){
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user.push(fn);
        },
        removeUser:function(fn){
            for (var i = 0; i < this.user.length; i++) {
                if(this.user[i] == fn)
                {
                    console.log(fn + "取消了订阅");
                    this.user.splice(i,1);
                }
            }
        },
        eat:function(){
            for (var i = 0; i < this.user.length; i++) {
               this.user[i]();
            }
        }
    }


    // 02 创建订阅者对象
    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        }
    }
    var tom = {
        eat_tom:function(){
            console.log("我陪你去吃寿司吧  ---tom");
        }
    }

    // 03 注册订阅者
    rose.addUser(jack.eat_jack);
    rose.addUser(tom.eat_tom);

    //04 发布者状态改变
    rose.eat();
    rose.removeUser(jack.eat_jack);
    rose.eat();
</script>
<script>
    //01 创建或者是设置一个发布者
    var publisher = {
        addUser:function(fn,type){
            var type = type || "eat";
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user[type].push(fn);
        },
        removeUser:function(fn,type){
            var type = type || "eat";
            for (var i = 0; i < this.user[type].length; i++) {
                if(this.user[type][i] == fn)
                {
                    console.log(fn + "取消了订阅");
                    this.user[type].splice(i,1);
                }
            }
        },
        eat:function(){
            for (var i = 0; i < this.user["eat"].length; i++) {
               this.user["eat"][i]();
            }
        },
        sleep:function(){
            for (var i = 0; i < this.user["sleep"].length; i++) {
                //console.log(this.user,"++++");
                this.user["sleep"][i]();
            }
        }
    }

    var rose = {};
    //封装一个函数用来快速的让某个指定对象成为发布者
    function makePublisher(o){
        for(var i in publisher)
        {
            if (publisher.hasOwnProperty(i) && typeof publisher[i] == "function" ){
                o[i] = publisher[i];
            }
        }
        o.user = {
            eat:[],
            sleep:[]
        };
    }
    makePublisher(rose);

    // 02 创建订阅者对象
    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        },
        sleep_jack:function(){
            console.log("晚安 rose  ---jack");
        }
    }

    // 03 注册订阅者
    rose.addUser(jack.eat_jack,"eat");        //关注rose肚子饿不饿
    rose.addUser(jack.sleep_jack,"sleep");     //关注rose困不困

    rose.eat();
    rose.sleep();
<script>
    //01 创建或者是设置一个发布者
    var publisher = {
        addUser:function(fn,type){
            var type = type || "eat";
            if (this.user[type] == undefined)
            {
                this.user[type] = [];
            }
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user[type].push(fn);
        },
        removeUser:function(fn,type){
            this.publish(type,fn);
        },
        publish:function(type,fn){
            var type = type || "eat";
            for (var i = 0; i < this.user[type].length; i++) {
                //判断当前是要取消订阅还是要发布状态
                if (typeof fn == "function")
                {
                    if(this.user[type][i] == fn)
                    {
                        console.log(fn + "取消了订阅");
                        this.user[type].splice(i,1);
                    }
                }else
                {
                    this.user[type][i]();
                }

            }
        }
    }
    var rose = {
        eat:function(){
            this.publish("eat");
        },
        sleep:function(){
            this.publish("sleep");
        },
        read:function(){
            this.publish("read");
        }
    };
    function makePublisher(o){
        for(var i in publisher)
        {
            if (publisher.hasOwnProperty(i) && typeof publisher[i] == "function" ){
                o[i] = publisher[i];
            }
        }
        o.user = {
            eat:[],
            sleep:[]
        };
    }
    makePublisher(rose);

    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        },
        sleep_jack:function(){
            console.log("晚安 rose  ---jack");
        }
    }
    var tom = {
        eat_tom:function(){
            console.log("我买给你吧  ---tom");
        },
        sleep_tom:function(){
            console.log("今晚的太阳很好看 ---tom");
        },
        read_tom:function(){
            console.log("你也在学习js吗?");
        }
    }

    rose.addUser(jack.eat_jack,"eat");
    rose.addUser(tom.sleep_tom,"sleep");
    rose.addUser(tom.read_tom,"read");
    rose.eat();
    rose.sleep();
    rose.read();

</script>
<script>
    //01 创建或者是设置一个发布者
    var publisher = {
        addUser:function(fn,type){
            var type = type || "eat";
            if (this.user[type] == undefined)
            {
                this.user[type] = [];
            }
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user[type].push(fn);
        },
        removeUser:function(fn,type){
            this.publish(type,fn);
        },
        publish:function(type,fn){
            var type = type || "eat";
            for (var i = 0; i < this.user[type].length; i++) {
                //判断当前是要取消订阅还是要发布状态
                if (typeof fn == "function")
                {
                    if(this.user[type][i] == fn)
                    {
                        console.log(fn + "取消了订阅");
                        this.user[type].splice(i,1);
                    }
                }else
                {
                    this.user[type][i]();
                }

            }
        }
    }
    var rose = {
        eat:function(){
            this.publish("eat");
        },
        sleep:function(){
            this.publish("sleep");
        },
        read:function(){
            this.publish("read");
        },
        lol_rose:function(){
            console.log("你怎么又在打游戏?还是游戏比较重要一些?")
        }
    };
    function makePublisher(o){
        for(var i in publisher)
        {
            if (publisher.hasOwnProperty(i) && typeof publisher[i] == "function" ){
                o[i] = publisher[i];
            }
        }
        o.user = {
            eat:[],
            sleep:[]
        };
    }
    makePublisher(rose);

    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        },
        sleep_jack:function(){
            console.log("晚安 rose  ---jack");
        },
        statusLol:function(){
            this.publish("lol");
        }
    }
    var tom = {
        eat_tom:function(){
            console.log("我买给你吧  ---tom");
        },
        sleep_tom:function(){
            console.log("今晚的太阳很好看 ---tom");
        },
        read_tom:function(){
            console.log("你也在学习js吗?");
        },
        lol_rose:function(){
            console.log("好兄弟,终于来啦");
        }
    }

    rose.addUser(jack.eat_jack,"eat");

    rose.addUser(tom.sleep_tom,"sleep");
    rose.addUser(tom.read_tom,"read");
    rose.eat();
    rose.sleep();
    rose.read();

    //设置jack成为发布者,状态(lol)
    makePublisher(jack);
    jack.addUser(rose.lol_rose,"lol");
    jack.addUser(tom.lol_rose,"lol");
    jack.statusLol();

</script>

备忘模式(函数结构缓存)

特定场合:

    f(n) ..... =>1000m
    代码中某些参数可能会反复计算
    f(10) ===>ssddd
    f(10) ===>ssddd

使用一个缓存对象cacheObj{key-value}

1.提供一个全局的对象(缓存对象),key-value
2.当我们传递参数需要进行计算(逻辑)的时候,先检查缓存对象中是否有对应的结果
3.如果有缓存数据,那么就直接使用(可以节省时间,提高效率)
4.如果没有缓存数据,那么这个时候再执行计算操作,处理得到结果之后,把这个数据保存起来
5.函数的参数作为缓存对象的key,把函数计算的结果作为这个key对应的值

<script>
    var cache = {};
    function f1(str){
        //.....
        if (cache[str] != undefined)
        {
            console.log("已经存在缓存数据,直接返回");
            return cache[str];
        }
        //....如果缓存中有数据,那么函数体后面的代码就不再执行(节省时间)

        //执行耗时操作...
        var result = str + " hello world!";
        cache[str] = result;
        console.log("第一次调用函数传入参数,返回结果");
        return result;
    }

    console.log(f1("demo"));   //
    console.log(f1("demo"));   //
    console.log(f1("demo"));
</script>
<script>
    function f1(str){
        //.....
        if (f1.cache[str] != undefined)
        {
            console.log("已经存在缓存数据,直接返回");
            return f1.cache[str];
        }
        //....如果缓存中有数据,那么函数体后面的代码就不再执行(节省时间)

        //执行耗时操作...
        var result = str + " hello world!";
        f1.cache[str] = result;
        console.log("第一次调用函数传入参数,返回结果");
        return result;
    }

    f1.cache = {};
    console.log(f1("test"));  //
    console.log(f1("test"));   //
    console.log(f1("test"));
</script>

命名空间模式:

写法:就是把所有的东西都写在一个对象里面.

命名:命名空间的名称一般是项目的名称或者是简写,要求所有的字符都大写

<script>
    //01 普通的变量
    var a = "a";
    var b = "b";

    //02 对象
    var obj = {
        name:"xxx"
    }

    function func (){
        console.log("func");
    }

    function Person(){
        this.name = "默认的名称";
    }
    function func (){
        console.log("func");
    }
</script>
<script>
    var MOMO = {};
    //01 普通的变量
    MOMO.a = "a";
    MOMO.b = "b";

    //02 对象
    MOMO.obj = {
        name:"zahngsan"
    }

    MOMO.func = function(){
        console.log("func");
    }

    MOMO.Person = function(){
        this.name = "默认的名称";
    }

    console.log(new  MOMO.Person());
</script>
<script>
//    var MOMO ={};
//    MOMO.obj = {
//        name:"张三"
//    };
//
//    MOMO.obj = "demodede";

    //在使用或者是对属性进行赋值之前,会先做一个检查(检查改属性或者是方法是否存在)
    //var MOMO = {};  不推荐

    //02 更安全的处理方式:麻烦
//    if (MOMO == undefined)
//    {
//        var MOMO = {};
//    }

    var MOMO = MOMO || {};      //逻辑或 如果MOMO为真那么返回MOMO,否则就返回{}
    //if (MOMO.name == undefined)
    if ( typeof MOMO.name == 'undefined')
{
    MOMO.name = "测试的名称";
}

    if ( typeof MOMO.age == 'undefined')
    {
        MOMO.age = 20;
    }

    //100属性

</script>

通用的命名空间函数

在命名空间上面提供一个方法(nameSpace)

<script>
    var MOMO = MOMO || {};
    MOMO.namespace = function(stringParam){
        var str = stringParam;
        var parts = str.split(".");   //根据字符串切割字符串变成一个数组
        var parent = MOMO;

        console.log(parts);

        if(parts[0] == "MOMO")
        {
            parts = parts.slice(1)    //作用:删除第一个元素返回一个新的数组
        }

        for (var i = 0; i < parts.length; i++) {
            //MOMO.name
            //name.des
            //des.abc
            if (parent[parts[i]] == undefined)
            {
                parent[parts[i]] = {};
            }
            //更新父节点
            parent = parent[parts[i]];
        }
    }

    MOMO.namespace("MOMO.name.des.abc");
    console.log(MOMO);

    MOMO.namespace("MOMO.a.b.c.d.e.f.d.g.h.j.k.s.d.g.h.j.a.s.d.f.we.r");
    console.log(MOMO);
    MOMO.namespace("abc.des.abc");
    console.log(MOMO);
</script>

截至今日,面向对象和JavaScript进阶内容已经全部更新完毕! 内容是比较详细的,只要跟着每一篇的博文仔细学习,比你看网上的垃圾视频强多了 ! 理论和实践相结合 更多的是得动手去敲,以后还请大家多多关注更新,日后定会上一些新颖的东西和大家见面 !


上一篇 下一篇

猜你喜欢

热点阅读