设计模式学习笔记

基于以下几个原则:

  • 开闭原则:软件应该对扩展开放,而对修改关闭。这里的意思是在增加新功能的时候,能不改代码就尽量不要改,如果只增加代码就完成了新功能,那是最好的。

  • 里氏替换原则:如果我们调用一个父类的方法可以成功,那么替换成子类调用也应该完全可以运行。

创建型模式

关注点是如何创建对象,其核心思想是要把对象的创建和使用相分离,这样使得两者能相对独立地变换。

工厂模式

工厂方法是指定义工厂接口和产品接口,但如何创建实际工厂和实际产品被推迟到子类实现,从而使调用方只和抽象工厂与抽象产品打交道。

实际更常用的是更简单的静态工厂方法,它允许工厂内部对创建产品进行优化。

调用方尽量持有接口或抽象类,避免持有具体类型的子类,以便工厂方法能随时切换不同的子类返回,却不影响调用方代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface NumberFactory {
// 创建方法:
Number parse(String s);

// 获取工厂实例:
static NumberFactory getFactory() {
return impl;
}
static NumberFactory impl = new NumberFactoryImpl();
}

public class NumberFactoryImpl implements NumberFactory {
public Number parse(String s) {
return new BigDecimal(s);
}
}

抽象工厂模式

抽象工厂模式是为了让创建工厂和一组产品与使用相分离,并可以随时切换到另一个工厂以及另一组产品;

抽象工厂模式实现的关键点是定义工厂接口和产品接口,但如何实现工厂与产品本身需要留给具体的子类实现,客户端只和抽象工厂与抽象产品打交道。

1
2
3
4
5
6
7
8
9
10
11
public class SimpleFactory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ProductA();
} else if (type.equals("B")) {
return new ProductB();
} else {
return null;
}
}
}

单例

单例模式是为了保证一个程序的运行期间,某个类有且只有一个全局唯一实例。单例模式既可以严格实现,也可以以约定的方式把普通类视作单例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}

public enum World {
// 唯一枚举:
INSTANCE;
private String name = "world";
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}

@Component
// Spring 表示一个单例组件
public class MyService {
}

生成器

生成器是为了创建一个复杂的对象,需要多个步骤完成创建,或者需要多个零件组装的场景,且创建过程中可以灵活调用不同的步骤或组件。

1
2
3
4
5
6
7
8
9
10
11
12
public class Builder {
private Product product = new Product();
public void buildPartA() {
product.add("part A");
}
public void buildPartB() {
product.add("part B");
}
public Product getResult() {
return product;
}
}

原型

原型模式是根据一个现有对象实例复制出一个新的实例,复制出的类型和属性与原实例相同。

1
2
3
4
5
public class Prototype implements Cloneable {
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

结构型模式

结构型模式主要涉及如何组合各种对象以便获得更好、更灵活的结构。虽然面向对象的继承机制提供了最基本的子类扩展父类的功能,但结构型模式不仅仅简单地使用继承,而更多地通过组合与运行期的动态组合来实现更灵活的功能。

适配器

Adapter模式可以将一个A接口转换为B接口,使得新的对象符合B接口规范。这样,就可以在不改变原有代码的情况下,将A接口的对象替换为B接口的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RunnableAdapter implements Runnable {
// 引用待转换接口:
private Callable<?> callable;
public RunnableAdapter(Callable<?> callable) {
this.callable = callable;
}
// 实现指定接口:
public void run() {
// 将指定接口调用委托给转换接口调用:
try {
callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

桥接

桥接模式通过分离一个抽象接口和它的实现部分,使得设计可以按两个维度独立扩展。

1
2
3
4
5
6
7
8
9
10
11
12
public class Bridge {
private Sourceable source;
public void method() {
source.method();
}
public Sourceable getSource() {
return source;
}
public void setSource(Sourceable source) {
this.source = source;
}
}

组合

Composite模式使得叶子对象和容器对象具有一致性,从而形成统一的树形结构,并用一致的方式去处理它们。

1
2
3
4
5
6
7
8
public interface Node {
// 添加一个节点为子节点:
Node add(Node node);
// 获取子节点:
List<Node> children();
// 输出为XML:
String toXml();
}

装饰

使用Decorator模式,可以独立增加核心功能,也可以独立增加附加功能,二者互不影响。可以在运行期动态地给核心功能增加任意个附加功能。

1
2
3
4
5
6
7
8
9
10
11
public abstract class NodeDecorator implements TextNode {
protected final TextNode target;

protected NodeDecorator(TextNode target) {
this.target = target;
}

public void setText(String text) {
this.target.setText(text);
}
}

外观

Facade模式是为了给客户端提供一个统一入口,并对外屏蔽内部子系统的调用细节。

1
2
3
4
5
6
7
8
9
10
public class Facade {
private SubSystemA a = new SubSystemA();
private SubSystemB b = new SubSystemB();
private SubSystemC c = new SubSystemC();
public void method() {
a.methodA();
b.methodB();
c.methodC();
}
}

享元

享元模式的设计思想是尽量复用已创建的对象,常用于工厂方法内部的优化。

1
2
3
4
5
6
7
8
9
10
11
12
public class Flyweight {
private Map<String, Flyweight> pool = new HashMap<String, Flyweight>();
public Flyweight getFlyweight(String key) {
if (pool.containsKey(key)) {
return pool.get(key);
} else {
Flyweight flyweight = new ConcreteFlyweight(key);
pool.put(key, flyweight);
return flyweight;
}
}
}

代理

代理模式通过封装一个已有接口,并向调用方返回相同的接口类型,能让调用方在不改变任何代码的前提下增强某些功能(例如,鉴权、延迟加载、连接池复用等)。使用Proxy模式要求调用方持有接口,作为Proxy的类也必须实现相同的接口类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Proxy implements Sourceable {
private Source source;
public void method() {
before();
source.method();
after();
}
private void before() {
System.out.println("before proxy!");
}
private void after() {
System.out.println("after proxy!");
}
}

行为型模式

行为型模式主要涉及算法和对象间的职责分配。通过使用对象组合,行为型模式可以描述一组对象应该如何协作来完成一个整体任务。

责任链

责任链模式是一种把多个处理器组合在一起,依次处理请求的模式。责任链模式的好处是添加新的处理器或者重新排列处理器非常容易。责任链模式经常用在拦截、预处理请求等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public interface Handler {
// 返回Boolean.TRUE = 成功
// 返回Boolean.FALSE = 拒绝
// 返回null = 交下一个处理
Boolean process(Request request);
}

public class HandlerChain {
// 持有所有Handler:
private List<Handler> handlers = new ArrayList<>();

public void addHandler(Handler handler) {
this.handlers.add(handler);
}

public boolean process(Request request) {
// 依次调用每个Handler:
for (Handler handler : handlers) {
Boolean r = handler.process(request);
if (r != null) {
// 如果返回TRUE或FALSE,处理结束:
System.out.println(request + " " + (r ? "Approved by " : "Denied by ") + handler.getClass().getSimpleName());
return r;
}
}
throw new RuntimeException("Could not handle request: " + request);
}
}

// 构造责任链:
HandlerChain chain = new HandlerChain();
chain.addHandler(new ManagerHandler());
chain.addHandler(new DirectorHandler());
chain.addHandler(new CEOHandler());
// 处理请求:
chain.process(new Request("Bob", new BigDecimal("123.45")));

命令

1
2
3
4
5
6
7
8
9
10
11
12
public class Command {
private Receiver receiver;
public void execute() {
receiver.action();
}
public Receiver getReceiver() {
return receiver;
}
public void setReceiver(Receiver receiver) {
this.receiver = receiver;
}
}

解释器

1
2
3
4
5
6
7
8
9
10
11
12
public class Interpreter {
private Context context;
public void interpret() {
context.interpret();
}
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
}

迭代器

1
2
3
4
5
6
7
8
9
10
11
12
public class Iterator {
private List list = new ArrayList();
public void add(Object obj) {
list.add(obj);
}
public void remove(Object obj) {
list.remove(obj);
}
public java.util.Iterator iterator() {
return list.iterator();
}
}

中介者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Mediator {
private ColleagueA a;
private ColleagueB b;
public void aChanged() {
b.action();
}
public void bChanged() {
a.action();
}
public ColleagueA getA() {
return a;
}
public void setA(ColleagueA a) {
this.a = a;
}
public ColleagueB getB() {
return b;
}
public void setB(ColleagueB b) {
this.b = b;
}
}

备忘录

1
2
3
4
5
6
7
8
9
public class Memento {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}

观察者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Observer {
private List<Observer> observers = new ArrayList<Observer>();
public void add(Observer observer) {
observers.add(observer);
}
public void remove(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}

状态

1
2
3
4
5
6
7
8
9
10
11
12
public class State {
private State state;
public void method() {
state.method();
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}

策略

1
2
3
4
5
6
7
8
9
10
11
12
public class Strategy {
private Strategy strategy;
public void method() {
strategy.method();
}
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
}

模板方法

1
2
3
4
5
6
7
8
9
10
11
12
public class TemplateMethod {
public void templateMethod() {
method1();
method2();
}
public void method1() {
System.out.println("method1");
}
public void method2() {
System.out.println("method2");
}
}

访问者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Visitor {
private List<Element> elements = new ArrayList<Element>();
public void add(Element element) {
elements.add(element);
}
public void remove(Element element) {
elements.remove(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}