Head First 设计模式 18-蝇量模式

又名 享元模式

如果想让一个类的一个实例能用来提供许多“虚拟实例”,就使用蝇量模式(Flyweight Pattern)。

书中以需要大量创建树对象的场景为例,如果采用带状态的树对象,需要耗费大量的内存。若改用虚拟树对象,可以显著的减少内存的消耗。

修改后的类图如下:

Head First 设计模式 17-责任链模式

当你想让一个以上的对象有机会能够处理某个请求的时候,就是用责任链模式(Chain of Responsibility Pattern)。

书中没有具体的代码示例,不过在 C# 中 delegate 类型可以很容易的实现这个模式。

示例代码及类图如下:

Head First 设计模式 16-生成器模式

生成器模式(Builder Pattern)封装一个产品的构造过程,并允许按步骤构造

这种模式在 ORMObject Relational Mapping 对象关系映射)框架的查询中经常能够遇到,很多框架都会提供类似 SqlBuilder 的功能。

书中以“主题公园”为例,通过生成器创建你的行程计划。其类图如下:

Head First 设计模式 15-桥接模式

桥接模式 通过将 实现抽象 放在 两个不同的类层次 中而使它们 可以独立改变

书中以遥控器和电视为例:不同按键模式的遥控器来遥控不同品牌的电视。其类图如下:

RemoteControl 抽象类 和 TV 接口及其实现类 两个层次之间的关系,就叫做 桥接

Head First 设计模式 14-复合模式

复合模式

模式通常被一起使用,并被组合在同一个设计解决方案中。

复合模式在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题。

书中以 MVCModel-View-Controller)为例,讲解了其中使用到的设计模式。

  • 策略模式

    视图是一个对象,可以被调整使用不同的策略,而控制器提供了策略。

  • 观察者模式

    模型实现了观察者模式,当模型的状态改变,相关视图对象也会跟着改变。

  • 组合模式

    视图是各种 UI 组件的组合。顶层的组件包含其它组件,直到叶节点。

Head First 设计模式 13-代理模式

代理模式 为一个对象提供一个替身或占位符以控制对这个对象的访问。

书中以 Java RMIRemote Method Invocation 远程方法调用)为例介绍的。

大概的实现步骤如下:

  1. 将远程接口的实现注册到 RMI registry
  2. 客户端从 RMI registry 查找并获取 stub(存根)。
  3. 客户像调用本地服务一样调用 stub 的方法。
Head First 设计模式 12-状态模式

状态模式 允许对象在内部改变状态时改变它的行为,对象看起来好像修改了它的类。

这个模式将状态封装成独立的类,并将动作委托到当前状态的对象,从而让行为随着状态改变而改变。

类图如下图所示。

状态模式 和 策略模式 比较相似。 策略模式 封装的是 算法状态模式 封装的是 状态。两者的区别在于它们的 “意图”

Head First 设计模式 11-组合模式

组合模式 允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

组合模式让我们能用 树形方式 创建对象的结构,树里面包含了组合以及个别的对象。

使用组合结构,我们能把 相同的操作 应用在 组合个别对象 上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。

Head First 设计模式 10-迭代器模式

迭代器模式 提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

书中示例是用 Java 写的,需要用到 java.util.Iterator 接口,C# 中对应的是 IEnumerator 接口,不过方法名稍有区别。

public interface IEnumerator
{
    object Current { get; }
    bool MoveNext();
    void Reset();
}
Head First 设计模式 09-模板方法模式

模板方法模式 在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

最常见的模板方法模式就是列表的排序方法了,C# 示例如下:

var arr = new List<string>() { "1", "3", "2" };
arr.Sort((a, b) => a.CompareTo(b));
Head First 设计模式 08-外观模式

外观模式 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

外观模式很好理解,其主要意图就是提供一个简单的接口,使子系统更容易使用。另外,外观模式不只是简化了接口,也将客户从组件的子系统中解耦。

外观和适配器 都可以包装许多类,但是外观的意图是 简化接口,而适配器的意图是 将接口转换成不同接口

Head First 设计模式 07-适配器模式

适配器模式 将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

类图如下:

Client:客户只看到目标接口。
Target:目标接口。
Adapter:适配器只看到目标接口。适配器与被适配者组合。
Adaptee:所有的请求都委托给被适配者。

Head First 设计模式 06-命令模式

命令模式 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。

书中分别列举了 遥控器餐厅下单 两个例子。

我的理解是 命令模式 主要目的是为了解耦 触发任务的对象实际执行的对象 ,即 调用者Invoker)和 接收者Receiver)。

Head First 设计模式 05-单件模式

单件模式 确保一个类只有一个实例,并提供一个全局访问点。

也叫 单例模式

这种模式在项目中还是比较常见的(如 线程池、缓存 等),理解起来也非常简单。

C# 中的常用写法如下。需要用到 lock 关键字,Java 中则需要使用 synchronized 关键字。

Head First 设计模式 04-工厂模式

工厂模式可能是项目中最常见的模式了,不过大部分使用的都是 简单工厂

简单工厂

简单工厂其实不是一种设计模式,反而比较像是一种编程习惯。

简单的示例如下:

class ProductFactory
{
    public Product CreateProduct(string type)
    {
        Product product = null;

        switch (type)
        {
            case "A":
                product = new ProductA();
                break;
            case "B":
                product = new ProductB();
                break;
            default:
                break;
        }

        return product;
    }
}
Head First 设计模式 03-装饰者模式

装饰者模式 动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

书中举例说在 java.io 包中有很多类都是装饰者,如 FileInputStreamFilterInputStream 等,不过感觉在项目倒是感觉很少用到。

各个装饰者之间的关系有点像俄罗斯套娃,一层层的包裹起来。暴露出来的是最外层的装饰者,访问时虽然表面上只访问了最外层的方法,但实际上从外到内依次调用到最底层的组件(有些类似于递归调用)。

Head First 设计模式 02-观察者模式

观察者模式 定义了对象之间一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

出版者 + 订阅者 = 观察者模式

说起来这个和 MQ 的生产者、消费者的概念比较类似,Apollo 配置中心也有类似的模式,再比如前端框架中数据和视图之间的绑定。

Head First 设计模式 01-策略模式

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,次模式让算法的变化独立于使用算法的客户。

如下类图所示,将 Duck 类的行为抽象为 Behavior 接口,然后在其子类 MallardDuck 中对 Behavior 属性指定其具体实现。

此种方式还有优点就是 Behavior 属性可以在运行时动态的改变,使系统的弹性更大。

设计原则

No.1

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。