目录

  • Head First Design Patterns
  • 1 设计原则(Design Principles)
  • 1.1 找出程序中的变化部分,然后将他们和不变的部分分开
  • 1.2 面向接口编程,而非实现
  • 1.3 多用组合,少用继承
  • 1.4 松耦合原则(Loose Coupling)
  • 1.5 开闭原则(Open-Closed)
  • 1.6 依赖倒置原则(Dependency Inversion)
  • 1.7 最少知识原则(Least Knowledge)
  • 1.8 好莱坞原则(Hollywood)
  • 1.9 单一职责原则(Single Responsibility)
  • 2 设计模式(Design Patterns)
  • 2.1 策略模式(Strategy)
  • 2.2 观察者模式(Observer)
  • 2.3 装饰者模式(Decorator)
  • 2.4 工厂方法模式(Factory Method)
  • 2.5 抽象工厂模式Abstract Factory
  • 2.6 单例模式Singleton
  • 2.7 命令模式Command
  • 2.8 适配器模式Adapter
  • 2.9 外观模式Facade
  • 2.10 模板方法模式Template Method
  • 2.11 迭代器模式Iterator
  • 2.12 组合模式Composite
  • 2.13 状态模式State
  • 2.14 代理模式Proxy
  • 2.15 复合模式Compound
  • ------ 以下模式使用频率相对较少 ------
  • 2.16 桥接模式Bridge
  • 2.17 生成器模式Builder
  • 2.18 责任链模式Chain of Responsibility
  • 2.19 享元模式Flyweight
  • 2.20 解释器模式Interpreter
  • 2.21 中介者模式Mediator
  • 2.22 备忘录模式Memonto
  • 2.23 原型模式Prototype
  • 2.24 访问者模式Visitor
  • 3 注意事项
  • 3.1 implement an interface
  • 3.2 Simple Factory
  • 4 关于设计模式的整体情况描述
  • 4.1 设计模式的定义
  • 4.2 各类设计模式的作用
  • 4.3 设计模式分类
  • 4.4 建议

Head First Design Patterns

最近看完了 Head First Design Patterns 2nd Edition,过程中做了一些笔记。

1 设计原则(Design Principles)

设计原则比设计模式更高一层,是站在更高的层次来指导我们的程序设计和编写。
当我们无法决定要不要使用模式,或者使用哪个模式时,就要以设计原则为指导。

1.1 找出程序中的变化部分,然后将他们和不变的部分分开

Identify the aspects of your application that vary and separate them from what stays the same!

Encapulate what varis.

1.2 面向接口编程,而非实现

Program to an interface, not an implementation!
注:此处的接口,并不仅仅指java中的interface,而是广义上的接口,可以理解为超类型;父型(supertype)。

1.3 多用组合,少用继承

Favor composition over inheritance.

1.4 松耦合原则(Loose Coupling)

Strive for loosely coupled designs between objects that interact.
为了交互对象间松耦合的设计而努力。

1.5 开闭原则(Open-Closed)

Classes should be open for extension, but closed for modification.
类应该对扩展开放,而对修改关闭。

1.6 依赖倒置原则(Dependency Inversion)

Depend upon abstractions. Do not depend upon concrete classes.
依赖抽象,不要依赖具体类。

The following guidelines can help you avoid OO designs that violate the Dependency Inversion Principle:

  1. No variable should hold a reference to a concrete class.
  2. No class should derive from a concrete class.
  3. No method should override an implemented method of any of its base classes.
    Note: Like many of our principles, this is a guideline you should strive for, rather than a rule you should follow all the time. Clearly, every single Java program ever written violates these guidelines!

1.7 最少知识原则(Least Knowledge)

Talk only to your immediate friends.
只和你的密友谈话。

The principle provides some guidelines: take any object, and from any method in that object, invoke only methods that belong to:

  1. The object itself.
  2. Objects passed in as a parameter to the method.
  3. Any object the method creates or instantiates.
  4. Any components of the object.

1.8 好莱坞原则(Hollywood)

Don't call us, we'll call you.
别调用(打电话给)我们,我们会调用(打电话给)你。

该原则是在模板方法设计模式中提出的,我之前的理解有一个误区,在模板方法的测试类的main()方法中,看到子类在调用父类的算法方法(algorithm method),就觉得是子类在调用父类的方法了,其实该原则指的不是在客户使用类框架时,而是指设计类框架时。在父类子类层次结构的设计中,子类中没有任何一个方法是调用父类中的方法的,只是实现父类的抽象方法,仅此而已;而父类的algorithm method中,却会调用子类中的方法。
扩展:包括其他的暂时理解有问题的内容,都可以想想是不是这方面的原因。

1.9 单一职责原则(Single Responsibility)

A class should have only one reason to change.
一个类应该只有一个引起变化的原因。

2 设计模式(Design Patterns)

2.1 策略模式(Strategy)

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

建议:

  1. build a community of pattern users. 建立一个模式用户社区(可以在自己组织内部,或者互联网上),大家相互交流学习。

2.2 观察者模式(Observer)

defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

2.3 装饰者模式(Decorator)

attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
动态地将职责附加到对象上。对于扩展功能,装饰者提供了比子类化更灵活的替代方案。

小结:

  1. 装饰者模式是通过组合而非继承获取到被装饰者的行为的,并且,此处的 组合,更具体、更准确的描述,是 包装(wrap)。也就是说, 包装组合 的其中一种方法。

2.4 工厂方法模式(Factory Method)

The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
工厂方法模式定义了一个创建对象的接口,但是让子类决定实例化哪个类。工厂方法推迟了一个类的实例化动作到子类。

在工厂方法模式中,又包含了3种子模式:

  1. 普通模式
    比如,利用条件从句来判断创建哪种对象。
  2. 动态工厂模式
    利用反射,根据传入的字符串参数来直接创建对象,而不需要条件从句的判断。
    传入的字符串参数不一定能匹配到某个已有的类,所以有可能抛出异常。
  3. 多态工厂模式
    利用匿名内部类、lambda表达式、方法引用等创建多个工厂类 A 的子类的实例,每个子类是创建不同的对象,然后将所有的子类放到另一个类 B 的集合成员或数组成员中(通过构造器添加工厂子类的实例到),对了,B是实现了 Supplier 函数式接口的。然后 通过 Stream.generate(new B(...)) 来创建多个对象。
    注意,B之所以实现 Supplier 接口,是为了使用流 Stream.generate(new B(...)) ,而这并不是必须的,可以不实现。

2.5 抽象工厂模式Abstract Factory

provides an interface for creating families of related or dependent objects without specifying their concrete classes.
提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

2.6 单例模式Singleton

ensures a class has only one instance, and provides a global point of access to it.
确保一个类只有一个实例,并提供一个全局访问点。

2.7 命令模式Command

encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
将请求封装成对象,从而使用不同的请求(队列请求、日志请求或事务请求,也支持可撤销操作的请求)来参数化其他对象。

2.8 适配器模式Adapter

converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
转换一个类的接口为客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

2.9 外观模式Facade

provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
提供了一个统一的接口,用来访问子系统中的一组接口。外观定义了一个高层接口,让子系统更容易使用。

2.10 模板方法模式Template Method

defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。

2.11 迭代器模式Iterator

provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
提供一种方法顺序访问聚合对象中的元素,而又不暴露其内部的表示。

2.12 组合模式Composite

allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
允许我们组合对象到树结构中,来表示“部分/整体”的层次结构。组合能让客户一致地处理单独对象和对象组合。

2.13 状态模式State

allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
允许对象在其内部状态改变时,改变其行为,该对象看起来就像是修改了它的类。

2.14 代理模式Proxy

provides a surrogate or placeholder for another object to control access to it.
为另一个对象提供了一个代理或占位符来控制对它的访问。

2.15 复合模式Compound

Combines two or more patterns into a solution that solves a recurring or general problem.
组合两个或以上的模式为一个解决方案,来解决某个常见或反复发生的问题。

eg. Java桌面客户端编程Swing 中的 MVC框架。


------ 以下模式使用频率相对较少 ------


2.16 桥接模式Bridge

vary not only your implementations, but also your abstractions.
不仅改变实现,也改变抽象。

2.17 生成器模式Builder

encapsulate the construction of a product and allow it to be constructed in steps.
封装产品的构建,并允许其按照步骤被构建。

2.18 责任链模式Chain of Responsibility

Use the Chain of Responsibility Pattern when you want to give more than one object a chance to handle a request.
当你想给予多个对象机会去处理某个请求时使用。

2.19 享元模式Flyweight

Use the Flyweight Pattern when one instance of a class can be used to provide many virtual instances.
当一个类的实例可被用于提供很多虚拟实例时使用。

flyweight:有道词典的解释如下:
n. (拳击或其他比赛中的)特轻量级选手,次最轻量级选手(体重48至51公斤) ;(拳击或其他比赛中的)特轻量级,蝇量级。

本意是指对象很轻很小的。直译就是 “苍蝇的重量”。想要表达它很轻的意思,在设计模式中,确实有这个意思,经过flyweight模式改进后,对象占用的内存比改进前小了很多,不占用太多系统内存、CPU资源了。
所以有的书中会直接翻译为 蝇量模式(如 Head First Design Patterns),强调对象的轻。
但是有的书中是翻译为 享元模式,其实也有道理,享元,享 是 共享,元 是 元素(即对象),意思是 共享的元素。它是强调对象的共享。
综上,两种翻译都可以,因为是站在2个不同的角度。

2.20 解释器模式Interpreter

build an interpreter for a language.
为语言构建解释器。

2.21 中介者模式Mediator

centralize complex communications and control between related objects.
集中相关对象之间的复杂的沟通和控制。

2.22 备忘录模式Memonto

Use the Memento Pattern when you need to be able to return an object to one of its previous states; for instance, if your user requests an “undo.”
当需要回退一个对象到它的前一个状态时使用,比如用户请求了“撤销”。

2.23 原型模式Prototype

Use the Prototype Pattern when creating an instance of a given class is either expensive or complicated.
当一个给定类实例的创建昂贵且复杂时使用。

2.24 访问者模式Visitor

Use the Visitor Pattern when you want to add capabilities to a composite of objects and encapsulation is not important.
当你想要给一个对象的组合添加新的能力,且封装并不重要时使用。

3 注意事项

3.1 implement an interface

in design patterns, the phrase “implement an interface” does NOT always mean “write a class that implements a Java interface, by using the ‘implements’ keyword in the class declaration.” In the general use of the phrase, a concrete class implementing a method from a supertype (which could be a abstract class OR interface) is still considered to be “implementing the interface” of that supertype.
设计模式中所谓的“实现一个接口”并不一定表示“写一个类,并在类声明中使用 implements 关键字来实现某个Java接口”。该短语的一般用法是,一个具体类实现某个超类型(可以是类或接口)的某个方法,则被认为是“实现该超类型的接口”。

3.2 Simple Factory

简单工厂,并不是一个设计模式,它只能算得上一个编程风格。
它仅仅将创建对象的代码提取到一个类中的一个方法中,该方法可以为普通方法,也能为静态方法。

4 关于设计模式的整体情况描述

4.1 设计模式的定义

  1. 设计模式的一个片面的定义:
    A Pattern is a solution to a problem in a context.
    一个(设计)模式是在某个情境下,针对某问题的某种解决方案。
    注意,该定义不足以描述真正的设计模式是什么!
  2. 书中,使用了“举出反例,然后证伪”的方法,来反驳该定义。
    反例:
    Problem:如何准时上班?
    Context:钥匙被锁在车里。
    Solution:打破窗玻璃,进入汽车,启动引擎,开车去上班。

为什么说该反例不是一个模式?

  • 无法平衡约束:成本。如果每次都用打破玻璃的方式,成本太高。
  • 无法适用于其他人的特定问题。(存疑,因为模式是解决一类通用问题,而非某些特殊问题)
  • 没有一个名字,无法和其他开发者共享。
  1. 最后,给出了正确定义的方法:模式类目(patterns catalogs)。
  2. 到哪里查看模式类目
    The first and most definitive patterns catalog is Design Patterns: Elements of Reusable Object-Oriented Software, by Gamma, Helm, Johnson, and Vlissides (Addison Wesley).
    第一个,也是最权威的设计类目来自于这本书:《设计模式:可复用面向对象软件的基础》。

4.2 各类设计模式的作用

Head First Design Patterns 2_ide

4.3 设计模式分类

分为3类:Creational(创建类), Structural(结构类),Behavioral(行为类):

  1. 创建类:即创建对象的⽅式。这通常涉及隔离对象创建的细节,以使代码不依赖于对象的类型,这 样在增加新对象类型时就不必做任何修改。
  2. 结构类:即如何设计满⾜特定项⽬约束的对象。这类设计主要围绕着这些对象和其他对象间的关联⽅式,以保证系统的变化不会导致这些关联⽅式的变化。
  3. ⾏为类:指处理程序中特定类型操作的对象。这些对象封装了要执⾏的流程,例如解释某种语⾔,满⾜某个请求,在序列中移动(⽐如通过迭代器),或者实现某种算法。

Head First Design Patterns 2_子类_02

4.4 建议

如果有简单的解决方案,就不用设计模式,因为设计模式虽然有巨大的优势,但往往会产生很多额外的类、对象、方法,导致系统性能的消耗增加。只有在必须要使用设计模式时,才使用它。