Design Pattern 基础设计模式
ShawJie

设计模式

目的:
设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。面向对象设计模式通常以类别或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类别或对象。设计模式能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免会引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力。


原则:
开闭原则:实现热插拔,提高扩展性。
里氏代换原则:实现抽象的规范,实现子父类互相替换;
依赖倒转原则:针对接口编程,实现开闭原则的基础;
接口隔离原则:降低耦合度,接口单独设计,互相隔离;
迪米特法则,又称不知道原则:功能模块尽量独立;
合成复用原则:尽量使用聚合,组合,而不是继承;

创建型模式

工厂模式

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决: 主要解决接口选择的问题。
何时使用: 我们明确地计划不同条件下创建不同实例时。
如何解决: 让其子类实现工厂接口,返回的也是一个抽象的产品。
关键代码: 创建过程在其子类执行。

图示:
image

工厂模式是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是”定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。”

1
2
//创建一个接口
public interface Shape { void draw(); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 //创建实现接口的实体类
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  class  ShapeFactory  {  
//使用 getShape 方法获取形状类型的对象
//若获取实例方法为Static(静态的)则是简单工厂模式
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
}else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
1
2
3
4
5
//调用工厂类
ShapeFactory factory = new ShapeFactory();
Shape shape = factory.getShap("CIRCLE");
shape = factory.getShap("RECTANGLE");
shape = factory.getShap("SQUARE");

总结:
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

抽象工厂

意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
主要解决:主要解决接口选择的问题。
何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决:在一个产品族里面,定义多个产品。
关键代码:在一个工厂里聚合多个同类产品。

图示:
image

抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道(或关心)它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。

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
//创建接口
public interface Button {}
public interface Border {}

//Mac系实体类
public class MacButton implements Button {}
public class MacBorder implements Border {}
//Win系实体类
public class WinButton implements Button {}
public class WinBorder implements Border {}

//创建工厂
public class MacFactory {
public static Button createButton() {
return new MacButton();
}
public static Border createBorder() {
return new MacBorder();
}
}
public class WinFactory {
public static Button createButton() {
return new WinButton();
}
public static Border createBorder() {
return new WinBorder();
}
}

单例模式

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。

图示:
image

实现:
我们将创建一个 SingleObject 类。SingleObject 类有它的私有构造函数和本身的一个静态实例。
SingleObject 类提供了一个静态方法,供外界获取它的静态实例。_SingletonPatternDemo_,我们的演示类使用 SingleObject 类来获取 _SingleObject_对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
* 主动模式(饿汉模式)
* 使用ClassLoader的特性保证了线程的安全
* 非Lazy Load模式,浪费了内存
*/
public class SingleObject{
//创建 SingleObject 的一个对象
private static SingleObject instance = new SingleObject();
//让构造函数为 private,这样该类就不会被实例化
private SingleObject(){}
//获取唯一可用的对象
public static SingleObject getInstance(){
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* 被动模式(懒汉模式)
* 线程不安全 若需线程安全 需给getInstance()加上Synchronized关键词
* 保证了线程安全但降低了效率
*/
public class SingleObject{
//创建一个SingleObject对象 但不实例化
private static SingleObject instance;
private SingleObject(){}
public static SingleObject getInstance(){
if(instance == null){
instance = new SingleObject();
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* Double-checked-locking模式
* 线程安全 且为Lazy Load加载方式
*/
public class SingleObject{
private static SingleObject instance;
private SingleObject(){}
public static SingleObject getInstance(){
if(instance == null){
synchronized(SingleObject.class){
if(instance == null)
instance = new SingleObject();
}
}
return instance;
}
}

生成器模式

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:主要解决在软件系统中,有时候面临着”一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

图示:
image

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
public class TableBuilderDemo {

public static void main(String[] args) {
(new TableBuilderDemo()).demo(args);
}

/**
* Client code perspective.
*/
public void demo(String[] args) {
// Name of the GUI table class can be passed to the app parameters.
String class_name = args.length > 0 ? args[0] : "JTable_Builder";

Builder target = null;
try {
target = (Builder) Class.forName(getClass().getName() + "$" + class_name)
.getDeclaredConstructor().newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}

String file_name = getClass().getResource("../BuilderDemo.dat").getFile();
TableDirector director = new TableDirector(target);
director.construct(file_name);
Component comp = target.get_result();

JFrame frame = new JFrame("BuilderDemo - " + class_name);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(comp);
frame.pack();
frame.setVisible(true);
}

interface Builder {
void set_width_and_height(int width, int height);

void start_row();

void build_cell(String value);

Component get_result();
}

public static class JTable_Builder implements Builder {
private JTable m_table;
private TableModel m_model;
private int x = 0, y = 0;

public void set_width_and_height(int width, int height) {
m_table = new JTable(height, width);
m_model = m_table.getModel();
}

public void start_row() {
x = 0;
++y;
}

public void build_cell(String value) {
m_model.setValueAt(value, y, x++);
}

public Component get_result() {
return m_table;
}
}

public static class GridLayout_Builder implements Builder {
private JPanel m_panel = new JPanel();

public void set_width_and_height(int width, int height) {
m_panel.setLayout(new GridLayout(height, width));
m_panel.setBackground(Color.white);
}

public void start_row() {
}

public void build_cell(String value) {
m_panel.add(new Label(value));
}

public Component get_result() {
return m_panel;
}
}

public static class GridBagLayout_Builder implements Builder {
private JPanel m_panel = new JPanel();
private GridBagConstraints c = new GridBagConstraints();
private int x = 0, y = 0;

public void set_width_and_height(int width, int height) {
m_panel.setLayout(new GridBagLayout());
m_panel.setBackground(Color.white);
}

public void start_row() {
x = 0;
++y;
}

public void build_cell(String value) {
c.gridx = x++;
c.gridy = y;
m_panel.add(new Label(value), c);
}

public Component get_result() {
return m_panel;
}
}

class TableDirector {
private Builder m_builder;

public TableDirector(Builder b) {
m_builder = b;
}

public void construct(String file_name) {
try {
BufferedReader br = new BufferedReader(new FileReader(file_name));
String line;
String[] cells;

if ((line = br.readLine()) != null) {
cells = line.split("\\t");
int width = Integer.parseInt(cells[0]);
int height = Integer.parseInt(cells[1]);
m_builder.set_width_and_height(width, height);
}

while ((line = br.readLine()) != null) {
cells = line.split("\\t");
for (int col = 0; col < cells.length; ++col) {
m_builder.build_cell(cells[col]);
}
m_builder.start_row();
}

br.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}

REFERENCES:Builder Pattern - SourceMaking

原型模式

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
主要解决:在运行期建立和删除原型。

图示:
image

1
2
3
4
5
6
7
8
9
/** Prototype Class **/
public class Cookie implements Cloneable {
public Object clone() throws CloneNotSupportedException
{
//In an actual implementation of this pattern you would now attach references to
//the expensive to produce parts from the copies that are held inside the prototype.
return (Cookie) super.clone();
}
}
1
2
/** Concrete Prototypes to clone **/
public class CoconutCookie extends Cookie { }
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
/** Client Class**/
public class CookieMachine
{

private Cookie cookie;//cookie必须是可复制的

public CookieMachine(Cookie cookie) {
this.cookie = cookie;
}

public Cookie makeCookie()
{
try
{
return (Cookie) cookie.clone();
} catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
return null;
}


public static void main(String args[]){
Cookie tempCookie = null;
Cookie prot = new CoconutCookie();
CookieMachine cm = new CookieMachine(prot); //设置原型
for(int i=0; i<100; i++)
tempCookie = cm.makeCookie();//通过复制原型返回多个cookie
}
}

REFERENCES:原型模式-维基百科

结构型模式

享元模式

意图:尽可能减少内存使用量以及分享资讯给尽可能多的相似物件。
主要解决:大量物件只是重复因而导致无法令人接受的使用大量内存。
如何解决:把它们放在外部数据结构,当需要使用时再将它们传递给享元。

1
2
3
public enum FontEffect {
BOLD, ITALIC, SUPERSCRIPT, SUBSCRIPT, STRIKETHROUGH
}
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public final class FontData {
/**
* A weak hash map will drop unused references to FontData.
* Values have to be wrapped in WeakReferences,
* because value objects in weak hash map are held by strong references.
* 一个WeakHashMap将自动GC未被引用的FontData
* 值必须被包裹在WeakReference中
* 因为值在WeakHashMap中依旧还是强引用状态
*/
private static final WeakHashMap<FontData, WeakReference<FontData>> FLY_WEIGHT_DATA =
new WeakHashMap<FontData, WeakReference<FontData>>();
private final int pointSize;
private final String fontFace;
private final Color color;
private final Set<FontEffect> effects;

private FontData(int pointSize, String fontFace, Color color, EnumSet<FontEffect> effects) {
this.pointSize = pointSize;
this.fontFace = fontFace;
this.color = color;
this.effects = Collections.unmodifiableSet(effects);
}

public static FontData create(int pointSize, String fontFace, Color color,
FontEffect... effects) {
EnumSet<FontEffect> effectsSet = EnumSet.noneOf(FontEffect.class);
for (FontEffect fontEffect : effects) {
effectsSet.add(fontEffect);
}
// We are unconcerned with object creation cost, we are reducing overall memory consumption
// 我们不关心对象创建成本,我们正在减少总体内存消耗
FontData data = new FontData(pointSize, fontFace, color, effectsSet);

// Retrieve previously created instance with the given values if it (still) exists
//如果(仍然)存在,则使用给定值检索先前创建的实例
WeakReference<FontData> ref = FLY_WEIGHT_DATA.get(data);
FontData result = (ref != null) ? ref.get() : null;

// Store new font data instance if no matching instance exists
// 如果不存在匹配的实例,则存储新的FontData实例
if (result == null) {
FLY_WEIGHT_DATA.put(data, new WeakReference<FontData> (data));
result = data;
}
// return the single immutable copy with the given values
// 返回具有给定值的单个不可变副本
return result;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof FontData) {
if (obj == this) {
return true;
}
FontData other = (FontData) obj;
return other.pointSize == pointSize && other.fontFace.equals(fontFace)
&& other.color.equals(color) && other.effects.equals(effects);
}
return false;
}

@Override
public int hashCode() {
return (pointSize * 37 + effects.hashCode() * 13) * fontFace.hashCode();
}

// Getters for the font data, but no setters. FontData is immutable.
// 获取FontData的getters,但没有setter。 FontData是不可变的。
}

总结:享元模式通过共用对象的方式 来减少数据对象的创建 减少内存的使用

代理模式

意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。

图示:
image

1
2
3
interface Image {
public void displayImage();
}
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
//on System A 
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}

private void loadImageFromDisk() {
System.out.println("Loading " + filename);
}

public void displayImage() {
System.out.println("Displaying " + filename);
}
}

//on System B
class ProxyImage implements Image {
private String filename;
private Image image;

public ProxyImage(String filename) {
this.filename = filename;
}
public void displayImage() {
if(image == null)
image = new RealImage(filename);
image.displayImage();
}
}
1
2
3
4
5
6
7
8
9
class ProxyExample {
public static void main(String[] args) {
Image image1 = new ProxyImage("HiRes_10MB_Photo1");
Image image2 = new ProxyImage("HiRes_10MB_Photo2");

image1.displayImage(); // loading necessary
image2.displayImage(); // loading necessary
}
}

总结:
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

外观模式

意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。
何时使用: 1、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个”接待员”即可。 2、定义系统的入口。
如何解决:客户端不与系统耦合,外观类与系统耦合。

图示:
image

Facade
这个外观类为子系统中Packages 1、2、3提供一个共同的对外接口
Clients
客户对象通过一个外观接口读写子系统中各接口的数据资源。
Packages
客户可以通过外观接口读取的内部库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* Complex parts */

class CPU {
public void freeze() { ... }
public void jump(long position) { ... }
public void execute() { ... }
}

class Memory {
public void load(long position, byte[] data) {
...
}
}

class HardDrive {
public byte[] read(long lba, int size) {
...
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* Façade */

class Computer {
public void startComputer() {
cpu.freeze();
memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE));
cpu.jump(BOOT_ADDRESS);
cpu.execute();
}
}

/* Client */

class You {
public static void main(String[] args) {
Computer facade = new Computer();
facade.startComputer();
}
}

总结:
优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。
缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

修饰模式

意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
如何解决:将具体功能职责划分,同时继承装饰者模式。

图示:
image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// The Window interface class
public interface Window {
// Draws the Window
public void draw();
// Returns a description of the Window
public String getDescription();
}


// implementation of a simple Window without any scrollbars
public class SimpleWindow implements Window {
public void draw() {
// Draw window
}

public String getDescription() {
return "simple window";
}
}
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// abstract decorator class - note that it implements Window
public abstract class WindowDecorator implements Window {
protected Window decoratedWindow; // the Window being decorated

public WindowDecorator (Window decoratedWindow) {
this.decoratedWindow = decoratedWindow;
}

@Override
public void draw() {
decoratedWindow.draw();
}

@Override
public String getDescription() {
return decoratedWindow.getDescription();
}
}


// The first concrete decorator which adds vertical scrollbar functionality
public class VerticalScrollBar extends WindowDecorator {
public VerticalScrollBar(Window windowToBeDecorated) {
super(windowToBeDecorated);
}

@Override
public void draw() {
super.draw();
drawVerticalScrollBar();
}

private void drawVerticalScrollBar() {
// Draw the vertical scrollbar
}

@Override
public String getDescription() {
return super.getDescription() + ", including vertical scrollbars";
}
}


// The second concrete decorator which adds horizontal scrollbar functionality
public class HorizontalScrollBar extends WindowDecorator {
public HorizontalScrollBar (Window windowToBeDecorated) {
super(windowToBeDecorated);
}

@Override
public void draw() {
super.draw();
drawHorizontalScrollBar();
}

private void drawHorizontalScrollBar() {
// Draw the horizontal scrollbar
}

@Override
public String getDescription() {
return super.getDescription() + ", including horizontal scrollbars";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Main {
// for print descriptions of the window subclasses
static void printInfo(Window w) {
System.out.println("description:"+w.getDescription());
}
public static void main(String[] args) {
// original SimpleWindow
SimpleWindow sw = new SimpleWindow();
printInfo(sw);
// HorizontalScrollBar mixed Window
HorizontalScrollBar hbw = new HorizontalScrollBar(sw);
printInfo(hbw);
// VerticalScrollBar mixed Window
VerticalScrollBar vbw = new VerticalScrollBar(hbw);
printInfo(vbw);
}
}

桥接模式

意图:将抽象部分与实现部分分离,使它们都可以独立的变化。
主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。
如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。

图示:
image

  • Abstraction
    定义抽象的接口
    该接口包含实现具体行为、具体特征的Implementor接口
  • Refined Abstraction
    抽象接口Abstraction的子类,依旧是一个抽象的事物名
  • Implementor
    定义具体行为、具体特征的应用接口
  • ConcreteImplementor
    实现Implementor接口
1
2
3
4
/** "Implementor" */
interface DrawingAPI{
public void drawCircle(double x, double y, double radius);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI{
public void drawCircle(double x, double y, double radius){
System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius);
}
}

/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI{
public void drawCircle(double x, double y, double radius){
System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius);
}
}
1
2
3
4
5
/** "Abstraction" */
interface Shape{
public void draw();// low-level
public void resizeByPercentage(double pct);// high-level
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/** "Refined Abstraction" */
class CircleShape implements Shape
{
private double x, y, radius;
private DrawingAPI drawingAPI;
public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI)
{
this.x = x; this.y = y; this.radius = radius;
this.drawingAPI = drawingAPI;
}

// low-level i.e. Implementation specific
public void draw()
{
drawingAPI.drawCircle(x, y, radius);
}
// high-level i.e. Abstraction specific
public void resizeByPercentage(double pct)
{
radius *= pct;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/** "Client" */
class BridgePattern {
public static void main(String[] args)
{
Shape[] shapes = new Shape[2];
shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());

for (Shape shape : shapes)
{
shape.resizeByPercentage(2.5);
shape.draw();
}
}
}

REFERENCES: 维基百科-桥接模式

适配器模式

意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
主要解决:主要解决在软件系统中,常常要将一些”现存的对象”放到新的环境中,而新环境要求的接口是现对象不能满足的。

图示:
image

Code:
image

1
2
3
4
//定义目标调用接口
interface Shape {
void draw(int x, int y, int z, int j);
}
1
2
3
4
5
6
7
8
9
10
11
12
class Line {
public void draw(int x1, int y1, int x2, int y2) {
System.out.println("Line from point A(" + x1 + ";" + y1 + "), to point B(" + x2 + ";" + y2 + ")");
}
}

class Rectangle {
public void draw(int x, int y, int width, int height) {
System.out.println("Rectangle with coordinate left-down point (" + x + ";" + y + "), width: " + width
+ ", height: " + height);
}
}
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
//实现Adapter
class LineAdapter implements Shape {
private Line adaptee;

public LineAdapter(Line line) {
this.adaptee = line;
}

@Override
public void draw(int x1, int y1, int x2, int y2) {
adaptee.draw(x1, y1, x2, y2);
}
}

class RectangleAdapter implements Shape {
private Rectangle adaptee;

public RectangleAdapter(Rectangle rectangle) {
this.adaptee = rectangle;
}

@Override
public void draw(int x1, int y1, int x2, int y2) {
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
int width = Math.abs(x2 - x1);
int height = Math.abs(y2 - y1);
adaptee.draw(x, y, width, height);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
//目标类的调用
public class AdapterDemo {
public static void main(String[] args) {
Shape[] shapes = {new RectangleAdapter(new Rectangle()),
new LineAdapter(new Line())};
int x1 = 10, y1 = 20;
int x2 = 30, y2 = 60;
for (Shape shape : shapes) {
shape.draw(x1, y1, x2, y2);
}
}
}

REFERENCE:Adapter Pattern - SourceMaking

行为型模式

访问者模式

意图:主要将数据结构与数据操作分离。
主要解决:稳定的数据结构和易变的操作耦合问题。
何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作”污染”这些对象的类,使用访问者模式将这些封装到类中。
如何解决:在被访问的类里面加一个对外提供接待访问者的接口。

图示:
image

Code:

  1. Add an accept(Visitor) method to the “element” hierarchy
  2. Create a “visitor” base class w/ a visit() method for every “element” type
  3. Create a “visitor” derived class for each “operation” to do on “elements”
  4. Client creates “visitor” objects and passes each to accept() calls
1
2
3
4
//创建对象访问回调接口
interface Element {
void accept(Visitor v);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class FOO implements Element {
public void accept(Visitor v) {
v.visit(this);
}

public String getFOO() {
return "FOO";
}
}

class BAR implements Element {
public void accept( Visitor v ) {
v.visit( this );
}

public String getBAR() {
return "BAR";
}
}
1
2
3
4
interface Visitor {
void visit(FOO foo);
void visit(BAR bar);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//创建访问者对象实例
class UpVisitor implements Visitor {
public void visit(FOO foo) {
System.out.println("do Up on " + foo.getFOO());
}

public void visit(BAR bar) {
System.out.println("do Up on " + bar.getBAR());
}
}

class DownVisitor implements Visitor {
public void visit(FOO foo) {
System.out.println("do Down on " + foo.getFOO());
}

public void visit(BAR bar) {
System.out.println("do Down on " + bar.getBAR());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Client 进行访问
public class VisitorDemo {
public static void main( String[] args ) {
Element[] list = {new FOO(), new BAR()};
UpVisitor up = new UpVisitor();
DownVisitor down = new DownVisitor();
for (Element element : list) {
element.accept(up);
}
for (Element element : list) {
element.accept(down);
}
}
}

REFERENCES:Visitor Design Pattern

模板方法模式

意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
何时使用:有一些通用的方法。
如何解决:将这些通用算法抽象出来。

图示:
image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
abstract class Game {
private int playersCount;
abstract void initializeGame();
abstract void makePlay(int player);
abstract boolean endOfGame();
abstract void printWinner();

/* A template method : */
final void playOneGame(int playersCount) {
this.playersCount = playersCount;
initializeGame();
int j = 0;
while (!endOfGame()){
makePlay(j);
j = (j + 1) % playersCount;
}
printWinner();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Now we can extend this class in order to implement actual games:

class Monopoly extends Game {
/* Implementation of necessary concrete methods */
void initializeGame() {/* ...*/ }
void makePlay(int player) {/* ...*/}
boolean endOfGame() {/* ...*/}
void printWinner() { /* ...*/}
/* Specific declarations for the Monopoly game. */
// ...
}

class Chess extends Game {
/* Implementation of necessary concrete methods */
void initializeGame() {/* ...*/}
void makePlay(int player) {/* ...*/}
boolean endOfGame() {/* ... */}
void printWinner() {/* ...*/}
/* Specific declarations for the chess game. */
// ...
}
1
2
3
4
5
6
7
public class Player {
public static void main(String[] args) {
Game chessGame = new Chess();
chessGame.initializeGame();
chessGame.playOneGame(1); //call template method
}
}

REFERENCES:模板方法 - 维基百科

策略模式

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。

图示:
image

1
2
3
4
// The context class uses this to call the concrete strategy
interface Strategy {
void execute();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Implements the algorithm using the strategy interface
class FirstStrategy implements Strategy {
public void execute() {
System.out.println("Called FirstStrategy.execute()");
}
}

class SecondStrategy implements Strategy {
public void execute() {
System.out.println("Called SecondStrategy.execute()");
}
}

class ThirdStrategy implements Strategy {
public void execute() {
System.out.println("Called ThirdStrategy.execute()");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Configured with a ConcreteStrategy object and maintains a reference to a Strategy object
class Context {

Strategy strategy;

// Constructor
public Context(Strategy strategy) {
this.strategy = strategy;
}

public void execute() {
this.strategy.execute();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class StrategyExample {
public static void main(String[] args) {

Context context;

// Three contexts following different strategies
context = new Context(new FirstStrategy());
context.execute();

context = new Context(new SecondStrategy());
context.execute();

context = new Context(new ThirdStrategy());
context.execute();
}
}

REFERENCES:策略模式 - 维基百科

状态模式

意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用:代码中包含大量与对象状态有关的条件语句。
如何解决:将各种具体的状态类抽象出来。

图示:
image

1
2
3
interface State {
void pull(CeilingFanPullChain wrapper);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CeilingFanPullChain {
private State currentState;

public CeilingFanPullChain() {
currentState = new Off();
}

public void set_state(State s) {
currentState = s;
}

public void pull() {
currentState.pull(this);
}
}
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
class Off implements State {
public void pull(CeilingFanPullChain wrapper) {
wrapper.set_state(new Low());
System.out.println("low speed");
}
}

class Low implements State {
public void pull(CeilingFanPullChain wrapper) {
wrapper.set_state(new Medium());
System.out.println("medium speed");
}
}

class Medium implements State {
public void pull(CeilingFanPullChain wrapper) {
wrapper.set_state(new High());
System.out.println("high speed");
}
}

class High implements State {
public void pull(CeilingFanPullChain wrapper) {
wrapper.set_state(new Off());
System.out.println("turning off");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class StateDemo {
public static void main(String[] args) {
CeilingFanPullChain chain = new CeilingFanPullChain();
while (true) {
System.out.print("Press ENTER");
getLine();
chain.pull();
}
}

static String getLine() {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = null;
try {
line = in.readLine();
} catch (IOException ex) {
ex.printStackTrace();
}
return line;
}
}

REFERENCES: State Design Pattern - SourceMaking

观察者模式

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。

图示:
image

1
2
3
4
5
//定义观察者父类
abstract class Observer {
protected Subject subject;
public abstract void update();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Subject {
private List<Observer> observers = new ArrayList<>();
private int state;

public void add(Observer o) {
observers.add(o);
}

public int getState() {
return state;
}

public void setState(int value) {
this.state = value;
execute();
}
//在更新后通知观察者
private void execute() {
for (Observer observer : observers) {
observer.update();
}
}
}
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
class HexObserver extends Observer {
public HexObserver(Subject subject) {
this.subject = subject;
this.subject.add(this);
}

public void update() {
System.out.print(" " + Integer.toHexString(subject.getState()));
}
}

class OctObserver extends Observer {
public OctObserver(Subject subject) {
this.subject = subject;
this.subject.add( this );
}

public void update() {
System.out.print(" " + Integer.toOctalString(subject.getState()));
}
}

class BinObserver extends Observer {
public BinObserver(Subject subject) {
this.subject = subject;
this.subject.add(this);
}

public void update() {
System.out.print(" " + Integer.toBinaryString(subject.getState()));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ObserverDemo {
public static void main( String[] args ) {
Subject sub = new Subject();
// Client configures the number and type of Observers
new HexObserver(sub);
new OctObserver(sub);
new BinObserver(sub);
Scanner scan = new Scanner(System.in);
for (int i = 0; i < 5; i++) {
System.out.print("\nEnter a number: ");
sub.setState(scan.nextInt());
}
}
}

REFERENCES: Observer Design Pattern

备忘录模式

意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
何时使用:很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有”后悔药”可吃。
如何解决:通过一个备忘录类专门存储对象状态。

图示:
image

1
2
3
4
5
6
7
8
9
10
11
class Memento {
private String state;

public Memento(String state) {
this.state = state;
}

public String getState() {
return state;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Originator {
private String state;
/* lots of memory consumptive private data that is not necessary to define the
* state and should thus not be saved. Hence the small memento object. */

public void setState(String state) {
System.out.println("Originator: Setting state to " + state);
this.state = state;
}

public Memento save() {
System.out.println("Originator: Saving to Memento.");
return new Memento(state);
}
public void restore(Memento m) {
state = m.getState();
System.out.println("Originator: State after restoring from Memento: " + state);
}
}
1
2
3
4
5
6
7
8
9
10
11
class Caretaker {
private ArrayList<Memento> mementos = new ArrayList<>();

public void addMemento(Memento m) {
mementos.add(m);
}

public Memento getMemento(int index) {
return mementos.get(index);
}
}

REFERENCES:Memento Design Pattern

中介者模式

意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
何时使用:多个类相互耦合,形成了网状结构。
如何解决:将上述网状结构分离为星型结构。

图示:
image

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
// 1. The "intermediary"
class Mediator {
// 4. The Mediator arbitrates
private boolean slotFull = false;
private int number;

public synchronized void storeMessage(int num) {
// no room for another message
while (slotFull == true) {
try {
wait();
}
catch (InterruptedException e ) {
Thread.currentThread().interrupt();
}
}
slotFull = true;
number = num;
notifyAll();
}

public synchronized int retrieveMessage() {
// no message to retrieve
while (slotFull == false) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
slotFull = false;
notifyAll();
return number;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Producer implements Runnable {
// 2. Producers are coupled only to the Mediator
private Mediator med;
private int id;
private static int num = 1;

public Producer(Mediator m) {
med = m;
id = num++;
}

@Override
public void run() {
int num;
while (true) {
med.storeMessage(num = (int)(Math.random()*100));
System.out.print( "p" + id + "-" + num + " " );
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Consumer implements Runnable {
// 3. Consumers are coupled only to the Mediator
private Mediator med;
private int id;
private static int num = 1;

public Consumer(Mediator m) {
med = m;
id = num++;
}

@Override
public void run() {
while (true) {
System.out.print("c" + id + "-" + med.retrieveMessage() + " ");
}
}
}
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
public class MediatorDemo {
public static void main( String[] args ) {
List<Thread> producerList = new ArrayList<>();
Scanner scanner = new Scanner(System.in);
System.out.println("Press ENTER for exit");
Mediator mb = new Mediator();
producerList.add(new Thread(new Producer(mb)));
producerList.add(new Thread(new Producer(mb)));
producerList.add(new Thread(new Consumer(mb)));
producerList.add(new Thread(new Consumer(mb)));
producerList.add(new Thread(new Consumer(mb)));
producerList.add(new Thread(new Consumer(mb)));
for (Thread p : producerList) {
p.start();
}
boolean stop = false;
String exit = scanner.nextLine();
while (!stop) {
if (exit.equals("")) {
stop = true;
for (Thread p : producerList) {
//noinspection deprecation
p.stop();
}
}
}
}
}

REFERENCES: Mediator Design Pattern

解释器模式

意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
主要解决:对于一些固定文法构建一个解释句子的解释器。
何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
如何解决:构件语法树,定义终结符与非终结符。

1
2
3
4
interface Operand {
double evaluate(Map<String, Integer> context);
void traverse(int level);
}
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
class Expression implements Operand {
private char operation;

public Operand left, right;

public Expression(char operation) {
this.operation = operation;
}
public void traverse(int level) {
left.traverse(level + 1);
System.out.print("" + level + operation + level + " ");
right.traverse(level + 1);
}

public double evaluate(Map<String, Integer> context) {
double result = 0;
double a = left.evaluate(context);
double b = right.evaluate(context);
if (operation == '+') {
result = a + b;
}
if (operation == '-') {
result = a - b;
}
if (operation == '*') {
result = a * b;
}
if (operation == '/') {
result = a / b;
}
return result;
}
}
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
class Variable implements Operand {
private String name;

public Variable(String name) {
this.name = name;
}

public void traverse(int level) {
System.out.print(name + " ");
}

public double evaluate(Map<String, Integer> context) {
return context.get(name);
}
}

class Number implements Operand {
private double value;

public Number(double value) {
this.value = value;
}

public void traverse(int level) {
System.out.print(value + " ");
}

public double evaluate(Map context) {
return value;
}
}
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public class InterpreterDemo {
public static boolean precedence(char a, char b) {
String high = "*/", low = "+-";
if (a == '(') {
return false;
}
if (a == ')' && b == '(') {
System.out.println(")-(");
return false;
}
if (b == '(') {
return false;
}
if (b == ')') {
return true;
}
if (high.indexOf(a) > - 1 && low.indexOf(b) > - 1) {
return true;
}
if (high.indexOf(a) > - 1 && high.indexOf(b) > - 1) {
return true;
}
//noinspection RedundantIfStatement
if (low.indexOf(a) > - 1 && low.indexOf(b) > - 1) {
return true;
}
return false;
}

public static String convertToPostfix(String expr) {
Stack<Character> operationsStack = new Stack<>();
StringBuilder out = new StringBuilder();
String operations = "+-*/()";
char topSymbol = '+';
boolean empty;
String[] tokens = expr.split(" ");
for (String token : tokens)
if (operations.indexOf(token.charAt(0)) == -1) {
out.append(token);
out.append(' ');
} else {
while (!(empty = operationsStack.isEmpty()) && precedence(topSymbol =
operationsStack.pop(), token.charAt(0))) {
out.append(topSymbol);
out.append(' ');
}
if (!empty) {
operationsStack.push(topSymbol);
}
if (empty || token.charAt(0) != ')') {
operationsStack.push(token.charAt(0));
} else {
topSymbol = operationsStack.pop();
}
}
while (!operationsStack.isEmpty()) {
out.append(operationsStack.pop());
out.append(' ');
}
return out.toString();
}

public static Operand buildSyntaxTree(String tree) {
Stack <Operand> stack = new Stack<>();
String operations = "+-*/";
String[] tokens = tree.split(" ");
for (String token : tokens)
if (operations.indexOf(token.charAt(0)) == -1) {
Operand term;
try {
term = new Number(Double.parseDouble(token));
} catch (NumberFormatException ex) {
term = new Variable(token);
}
stack.push(term);

// If token is an operator
} else {
Expression expr = new Expression(token.charAt(0));
expr.right = stack.pop();
expr.left = stack.pop();
stack.push(expr);
}
return stack.pop();
}

public static void main(String[] args) {
System.out.println("celsius * 9 / 5 + thirty");
String postfix = convertToPostfix("celsius * 9 / 5 + thirty");
System.out.println(postfix);
Operand expr = buildSyntaxTree(postfix);
expr.traverse(1);
System.out.println();
HashMap < String, Integer > map = new HashMap<>();
map.put("thirty", 30);
for (int i = 0; i <= 100; i += 10) {
map.put("celsius", i);
System.out.println("C is " + i + ", F is " + expr.evaluate(map));
}
}
}

REFERENCES:Interpreter Design Pattern

命令模式

意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
何时使用:在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。

图示:
image

Code:

1
2
3
4
/* The Command interface */
public interface Command {
void execute();
}
1
2
3
4
5
6
7
8
9
10
11
12
/* The Invoker class */
public class Switch {
private List<Command> history = new ArrayList<Command>();

public Switch() {
}

public void storeAndExecute(Command cmd) {
this.history.add(cmd); // optional
cmd.execute();
}
}
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
37
38
39
/* The Receiver class */
public class Light {
public Light() {
}

public void turnOn() {
System.out.println("The light is on");
}

public void turnOff() {
System.out.println("The light is off");
}
}

/* The Command for turning on the light - ConcreteCommand #1 */
public class FlipUpCommand implements Command {
private Light theLight;

public FlipUpCommand(Light light) {
this.theLight = light;
}

public void execute(){
theLight.turnOn();
}
}

/* The Command for turning off the light - ConcreteCommand #2 */
public class FlipDownCommand implements Command {
private Light theLight;

public FlipDownCommand(Light light) {
this.theLight = light;
}

public void execute() {
theLight.turnOff();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* The test class or client */
public class PressSwitch {
public static void main(String[] args){
Light lamp = new Light();
Command switchUp = new FlipUpCommand(lamp);
Command switchDown = new FlipDownCommand(lamp);

Switch mySwitch = new Switch();

try {
if ("ON".equalsIgnoreCase(args[0])) {
mySwitch.storeAndExecute(switchUp);
}
else if ("OFF".equalsIgnoreCase(args[0])) {
mySwitch.storeAndExecute(switchDown);
}
else {
System.out.println("Argument \"ON\" or \"OFF\" is required.");
}
} catch (Exception e) {
System.out.println("Arguments required.");
}
}
}

REFERENCES: 命令模式 - 维基百科

责任链模式

意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
何时使用:在处理消息的时候以过滤很多道。
如何解决:拦截的类都实现统一接口。

图示:
image
Code:

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
abstract class Logger 
{
public static int ERR = 3;
public static int NOTICE = 5;
public static int DEBUG = 7;
protected int mask;

// The next element in the chain of responsibility
protected Logger next;
public Logger setNext( Logger l)
{
next = l;
return this;
}

public final void message( String msg, int priority )
{
if ( priority <= mask )
{
writeMessage( msg );
if ( next != null )
{
next.message( msg, priority );
}
}
}

protected abstract void writeMessage( String msg );

}
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
class StdoutLogger extends Logger 
{

public StdoutLogger( int mask ) { this.mask = mask; }

protected void writeMessage( String msg )
{
System.out.println( "Writting to stdout: " + msg );
}
}


class EmailLogger extends Logger
{

public EmailLogger( int mask ) { this.mask = mask; }

protected void writeMessage( String msg )
{
System.out.println( "Sending via email: " + msg );
}
}

class StderrLogger extends Logger
{

public StderrLogger( int mask ) { this.mask = mask; }

protected void writeMessage( String msg )
{
System.out.println( "Sending to stderr: " + msg );
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ChainOfResponsibilityExample
{
public static void main( String[] args )
{
// Build the chain of responsibility
Logger l = new StdoutLogger( Logger.DEBUG).setNext(
new EmailLogger( Logger.NOTICE ).setNext(
new StderrLogger( Logger.ERR ) ) );

// Handled by StdoutLogger
l.message( "Entering function y.", Logger.DEBUG );

// Handled by StdoutLogger and EmailLogger
l.message( "Step1 completed.", Logger.NOTICE );

// Handled by all three loggers
l.message( "An error has occurred.", Logger.ERR );
}
}

REFERENCES: 责任链模式 - 维基百科