设计模式(上)

JAVAScript 创建对象 的13设计模式(上)


要掌握设计模式,首先接触的是 高阶函数(higher-order function)[1]

高阶函数的应用:

  • 回调函数:

    • 事件、ajax、所有涉及到异步通信的几乎都是回调函数()node.js
  • dom事件

一、单例模式

理论: 整个程序只包含一个实例;保证实例公有一个类,
并提供一个访问它的全局访问点(实例化的都指向同一区域)。

优点:节约内存;在 JavaScript 里,单例作为一个命名空间提供者,
从全局命名空间里提供一个唯一的访问点来访问该对象,避免全局污染。

缺点:字面量实现方式即使不用也占用内存,延迟方式,
当调用 getInstance的时候才分配内存,如果单例对象非常复杂,
则延迟模式(惰性加载)更好。

1 字面量形式

    通过 对象字面量 的形式(json格式)

var obj = {
    name: 'wang',
    showName: function() {
        console.log(this.name);
    }
};
var o1 = obj;
var o2 = obj;
<!-- o1 === o2 -->
// 复杂类型是将obj变量存于栈中,通过指针指向堆中的存储空间

2.通过 构造函数 的方式(改变指针指向,确保只开辟一个空间)

function Obj(){
    <!-- 为保证只有一个实例,定义一个变量,判断是否有该实例 -->
    if(Obj.a !== undefined) {
        //第二次实例化的时候通过保存的变量改变指针
        return Obj.a;
    }
    this.sum = 0;
    this.getPrice = function(price){
        this.sum += price;
        return this.sum;
    };
    // 保存变量(关键)
    Obj.a = this;
}
var o1 = new Obj();
var o2 = new Obj();
o1 === o2             // 值 与 类型都相同(后端语言包含地址)

3.函数 闭包 链式访问形式(命名空间)

var Product = (function() {
    var unique;
    var sum = 0;
    // 判断函数
    function getInstance() {
        if(!unique) {
            unique = construct();
        };
        return unique;
    };
    // 保存单利对象的函数
    function construct() {
        return {
            getPrice: function() {},
            addCart: function() {}
            // 可以保存更多的方法及属性
        };
    };
})();
// 链式调用方法
Product.getInstance().getPrice();

二、工厂模式

理论:通过使用工厂方法而不是new关键字及具体类,把所有实例化的代码都集中在一个位置。

优点:有助于创建模块化的代码,消除对象之间的耦合。

  • 大型项目扩展影响小
  • 有助于提高项目的扩展性、灵活性
  • 封装性(封装创建过程)

缺点:

  • 新增流水线,将不利于改造

1.普通方式

    函数内部实例,并返回对象

function Obj(name) {
    // 创建对象,并对对象拓展属性及方法
    var o = new Object();
    o.name = name;
    o.show = function() {
        alert(this.name);
    }
    // 将对象返回
    return o;
};
<!-- 创建需要的obj -->
var doSome = Obj('wang');
<!-- obj1 == obj2  // false -->

2.零模式

(1)工厂对象

var Factory = function() {};  //构建工厂
Factory.prototype = {         //工厂返回实例
    create:function(type){
        var product;
        switch(type) {
            case:'one':
                product = new OnePro();
                break;
            case:'two':
                product = new TwoPro();
                break;
        }
        return product;
    }
};
// 通过工厂返回相应的实例,而不是this的链式访问

// 定义 products 分类
var OnePro = function() {};   // 分类一
OnePro.prototype = {
    name: 'one',
    getName:function(){
        return this.name;
    }
} 
var TwoPro = function() {};   // 分类二
TwoPro.prototype = {
    name: 'two',
    getName:function(){
        return this.name;
    }
}

(2)工厂函数

function factory(type) {
    var product;
    switch(type) {
        case:'one':
            product = new OnePro();
            break;
        case:'two':
            product = new TwoPro();
            break;
    };
    return product;
};
// 直接调用函数即可创建分类对象

3.普通函数采用工厂模式实现new

4.团队应用工厂模式

(1)团队一、算法:

var Price = {};    // 创建命名空间
Price.vip = function() {    // 分类一
    this.dis = 0.3;
    this.getPrice = function(price) {
        return price * this.dis;
    }
};
Price.old = function() {    // 分类二
    this.dis = 0.5;
    this.getPrice = function(price) {
        return price * this.dis;
    }
};
Price.normal = function() {    // 分类三
    this.dis = 0.7;
    this.getPrice = function(price) {
        return price * this.dis;
    }
};
// 对新增分类有好处 直接添加即可

(2)团队二、

<!-- 生产不同的实例 不关心如何定义 -->
Price.factory = function(type){
    return new Price[type]
}

(3)团队三、

<!-- 使用对象的接口 不关心内部构造 -->
var nomalPrice = Price.factory('normal');
nomalPrice.getPrice(1000);

三、策略模式[2]

步骤:

  • 定义算法对象
    • 算法对象是为了解决频繁的扩展方法问题
  • 定义上下文
    • 上下文是为了框架的使用简洁化,不用关心算法细节
  • 使用

优点:解耦合   模块化

应用:

  • 保护核心系统
  • 屏蔽复杂对象
  • 延迟加载
    • 通过代理模式实现延迟加载
    • jqurey插件实现延迟加载

1.策略模式

<!-- 定义不同的计算函数 -->
var vip = function(price) {
    return price * 0.3;  //执行算法代码
};
var old = function(price) {
    return price * 0.5;  //执行算法代码
};
var nomal = function(price) {
    return price * 0.7;  //执行算法代码
};
// 定义调用函数部分(定义上下文)
var calculate = function(fn,price){
    return fn(price);
};
// 使用部分 
var price = calculate(vip,1000);

2.类反射方式

<!-- 定义对象  存放各 类 的计算方法 -->
var class = {
    "vip":function(price) {
        return price * 0.3;  //执行算法代码
    },
    "old":function(price) {
        return price * 0.5;  //执行算法代码
    },
    "nomal":function(price) {
        return price * 0.7;  //执行算法代码
    }
};
// 全局污染减少 
var calculate = function(leval,price){
    // 反射机制
    return class[leval](price);
};
// 使用部分 
var price = calculate("vip",1000);

四、观察者模式(Observer):双向绑定的本质

理论: 又称作:表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式、从属者(Dependents)模式、

  • 注册:
    • dom事件入队列(存入数组)
  • 监听:
    • 执行事件
  • 响应:
    • 执行回调函数

       1.观察者模式其实就是实现异步编程,javascript本身就是支持异步编程的语言。这是它的强大之处。
       2.观察者模式是利用函数回调来实现异步编程,当事件触发时,所有订阅者都会受到消息,并调用对应的处理函数,而不用实时监测,这显然在某些情况下,极大的提高了cpu的利用率。
       3.自定义事件就是异步编程的实际运用,让你可以将操作代码在你想要执行的时候去执行(触发事件),而不是传统的从上到下执行,增加了代码灵活性。并且,减少 了代码冗余,同样的操作,只需要触发同样的事件就行了,不需要再写一遍。

优点:

  • 支持简单的广播通信,自动通知所有已经订阅过的对象
  • 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性
  • 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用(高内聚,低耦合)

缺点:

扩充----事件轮询(Event Loop)[^3]
[^3]:指的是计算机系统的一种运行机制。(JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。);主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件轮询)

什么是进程:
        一般情况下,一个进程一次只能执行一个任务。如果有很多任务需要执行,不外乎三种解决方法。        (1)排队:因为一个进程一次只能执行一个任务,只好等前面的任务执行完了,再执行后面的任务。        (2)新建进程:使用fork命令,为每个任务新建一个进程。        (3)新建线程:因为进程太耗费资源,所以如今的程序往往允许一个进程包含多个线程,由线程去完成任务。
>

五、代理模式

理论:代理模式就是用一个类来代替另一个类来执行方法功能

优点:

缺点:

六、装饰者模式

理论:

优点:

缺点:


  1. 如果一个函数接收的参数为或返回的值为函数,那么我们可以将这个函数称为高阶函数。 ↩︎

  2. (1)工厂模式解决了多种判断不需要if语句的问题,当新增属性或方法时,只需要从新定义一个对象即可,原有代码无需修改。
    (2)策略模式和工厂模式类似,只不过策略模式解决的是算法家族问题而不是对象实例问题。 ↩︎

原文地址:https://www.cnblogs.com/jwen/p/5416365.html