设计模式摘录

187 阅读5分钟

代理模式

定义:为一个对象提供一个代用品或者占位符,以便控制它的访问。

当我们不方便直接访问某个对象的时候,或者不满足需求时,可考虑使用一个替身对象来控制该对象的访问。替身对象可对请求预先进行处理,再决定是否转交给本体对象。

模式特点

  1. 代理对象可预先请求处理,再决定是否转交给本体;
  2. 代理和本体对外显示接口保持一致性
  3. 代理对象仅对本体做一次包装

模式细分

  1. 虚拟代理(将开销大的运算延迟到需要时执行)
  2. 缓存代理(为开销大的运算结果提供缓存)
  3. 保护代理(黑白双簧,代理充当黑脸,拦截非分要求)
  4. 防火墙代理(控制网络资源的方向)

在 JS 中常常会用到的代理模式为 ”虚拟代理“ 和 ”缓存代理“.

适用场景

  • 虚拟代理
    • 图片预加载(loading 图)
    • 合并 HTTP 请求(数据上报汇总)
  • 缓存代理:(前提本体是纯函数)
    • 缓存异步请求数据
    • 缓存较为复杂的运算结果

接下来看两个具体的例子:

虚拟代理

虚拟代理的目的,是将开销大的运算延迟到需要时再执行。

我们来看一个虚拟代理在图片预加载的应用。

// 本体
var myImage = (function () {
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);
    return {
        setSrc: function (src) {
            imgNode.src = src;
        }
    };
})();

// 代理
var proxyImage = (function () {
    var img = new Image();
    img.onload = function () {
				// 图片加载完设置真实图片 src
        myImage.setSrc(this.src);
    };
    return {
        setSrc: function (src) {
            // 预先设置图片 src 为 loading 图
						myImage.setSrc('./loading.gif');
            img.src = src;
        }
    };
})();

// 外部调用
proxyImage.setSrc('./product.png');

缓存代理(暂时储存)

缓存代理的目的,是为一些开销大的运算结果提供暂时存储,以便下次调用时,参数与结果不变情况下,从缓存返回结果,而不是重新进行本体运算,减少本体调用次数。

var add = function () {
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
};
var proxyAdd = (function () {
    var cache = {}; //缓存运算结果的缓存对象
    return function () {
        var args = Array.prototype.join.call(arguments); //把参数用逗号组成一个字符串作为“键”
        if (cache.hasOwnProperty(args)) {
            //等价 args in cache
            console.log('使用缓存结果');
            return cache[args]; //直接使用缓存对象的“值”
        }
        console.log('计算结果');
        return (cache[args] = add.apply(this, arguments)); //使用本体函数计算结果并加入缓存
    };
})();
console.log(proxyAdd(1, 2, 3, 4, 5));
console.log(proxyAdd(1, 2, 3, 4, 5));
console.log(proxyAdd(1, 2, 3, 4, 5));

复合模式

复合模式结合两个或者两个以上的模式,组成一个解决方案,解决一再发生的一般性问题

MVC 与复合模式

mvc 框架就是一个典型的复合模式

  • 观察者模式:V和C都是M的观察者(Model的状态更新要及时通知V更新视图,或者通知C做相应逻辑处理)
  • 策略模式:C是V的“策略”,所以V包含的控制逻辑就是“选择策略”,也就是选择控制器Controller
  • 组合模式:V的自身实现应用了组合模式(调用顶层容器的repaint方法,容器内的所有组件都会重绘)

与设计模式相处

定义设计模式

模式是在某情境下,针对某问题的某种解决方案

设计模式分类

1、创建型模式

创建型模式涉及到将对象实例化,这类模式都提供一个方法,将客户从所需要实例化的对象中解耦。

  • 工厂方法模式:由子类决定要创建的具体类是哪一个。
  • 抽象工厂模式:允许客户创建对象的家族,而无需指定它们的具体类。
  • 单件模式(单例模式):确保有且只有一个对象被创建。
  • 生成器模式(建造者模式):封装一个复杂对象的创建过程。
  • 原型模式:通过复制现有的实例来创建新的实例。

2、行为型模式

行为型模式涉及到类和对象如何交互及分配职责。

  • 策略模式:封装可以互换的行为,并使用委托来决定要使用哪一个。
  • 观察者模式:让对象能够在状态改变时被通知。
  • 命令模式:封装请求成为对象。
  • 模板方法模式:由子类决定如何实现一个算法中的步骤。
  • 迭代器模式:在对象的集合之中游走,而不暴露集合的实现。
  • 状态模式:封装了基于状态的行为,并使用委托在行为之间切换。
  • 责任链模式:为某个请求创建一个对象链。
  • 解释器模式:将每一个语法规则表示成一个类。
  • 中介者模式:封装一系列对象之间的交互。
  • 备忘录模式:在对象外部存储对象的某个状态。
  • 访问者模式:通过访问数据结构中的每个元素,来对元素进行各种操作。

3、结构型模式

结构型模式涉及到类和对象如何被组合以建立新的结构或新的功能。

  • 装饰者模式:包装一个对象,以提供新的行为。
  • 适配器模式:封装对象,并提供不同的接口。
  • 外观模式:简化一群类的接口。
  • 组合模式:客户用一致的方式处理对象集合和单个对象。
  • 代理模式:包装对象,以控制对此对象的访问。
  • 桥接模式:分离抽象与实现,使它们可以独立变化。
  • 蝇量模式(享元模式):运用共享技术,减少对象的创建。