行为型模式-备忘录模式

百度百科

备忘录模式

备忘录模式是一种软件设计模式:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

基本介绍

备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式,是GoF的23种设计模式之一,属于行为模式。

定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

涉及角色:

  1. Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。
  2. Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
  3. Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。

备忘录模式的优点和缺点

一、 备忘录模式的优点

  1. 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,
    使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。

  2. 本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所需
    要的这些状态的版本。

    二、 备忘录模式的缺点:

  3. 如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。

  4. 当负责人角色将一个备忘录 存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很昂贵。

  5. 当发起人角色的状态改变的时候,有可能这个协议无效。如果状态改变的成功率不高的话,不如采取“假如”协议模式。

例子

Memento
备忘录存储原发器对象的内部状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Memento {
private String state;

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

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}
}

Originator
原发器创建一个备忘录,用以记录当前时刻的内部状态。
使用备忘录恢复内部状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Originator {
private String state;

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}

public Memento createMemento(){
return new Memento(state);
}
public void setMemento(Memento memento){
state=memento.getState();
}
public void showState(){
System.out.println(state);
}
}

Caretaker
负责保存好备忘录。
不能对备忘录的内部进行操作或检查。

1
2
3
4
5
6
7
8
9
10
11
public class Caretaker {
private Memento memento;

public Memento getMemento() {
return memento;
}

public void setMemento(Memento memento) {
this.memento = memento;
}
}

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Test {
public static void main(String[] args) {
Originator org = new Originator();
org.setState("开会中");

Caretaker ctk = new Caretaker();
ctk.setMemento(org.createMemento());//将数据封装在Caretaker

org.setState("睡觉中");
org.showState();

org.setMemento(ctk.getMemento());
org.showState();
}
}

运行结果

1
2
睡觉中
开会中

行为型模式-解释器模式

百度百科

Interpreter模式

Interpreter(解释器)模式是一种特殊的设计模式,它建立一个解释器(Interpreter),对于特定的计算机程序设计语言,用来解释预先定义的文法。简单地说,Interpreter模式是一种简单的语法解释器构架。

Interpreter模式,即解释器模式。

解释器模式属于行为模式,Gof是这样定义的:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

实例应用:正则表达式

例子

AbstractExpression(抽象表达式)
声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。

1
2
3
public abstract class Expression {
abstract void interpret(Context ctx);
}

TerminalExpression(终结符表达式)
实现与文法中的终结符相关联的解释操作。
一个句子中的每个终结符需要该类的一个实例。

1
2
3
4
5
6
public class SimpleExpression extends Expression {
@Override
void interpret(Context ctx) {
System.out.println("这是普通解析器");
}
}

NonterminalExpression(非终结符表达式)
为文法中的非终结符实现解释(Interpret)操作。

1
2
3
4
5
6
public class AdvanceExpression extends Expression {
@Override
void interpret(Context ctx) {
System.out.println("这是高级解析器");
}
}

Context(上下文)
包含解释器之外的一些全局信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.List;

public class Context {
private String content;
private List list = new ArrayList();

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public void add(Expression eps){
list.add(eps);
}
public List getList(){
return list;
}
}

Client(客户)
构建(或被给定)表示该文法定义的语言中某个特定的句子的抽象语法树。
该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。调用解释操作。

1
2
3
4
5
6
7
8
9
10
11
public class Test {
public static void main(String[] args) {
Context ctx = new Context();
ctx.add(new SimpleExpression());
ctx.add(new AdvanceExpression());
ctx.add(new SimpleExpression());
for(Object eps: ctx.getList()){
((Expression)eps).interpret(ctx);
}
}
}

运行结果

1
2
3
这是普通解析器
这是高级解析器
这是普通解析器

结构型模式-组合模式

百度百科

组合模式

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。

组合模式可以让客户端像修改配置文件一样简单的完成本来需要流程控制语句来完成的功能。

经典案例:系统目录结构,网站导航结构等。

组合模式概述

组合模式(Composite Pattern)

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。

有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。

定义

(GoF《设计模式》):将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

涉及角色:

  1. Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
  2. Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。
  3. Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

适用性

以下情况下适用Composite模式:

  1. 你想表示对象的部分-整体层次结构
  2. 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

总结

组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以像处理简单元素一样来处理复杂元素。

如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。本章使用了一个文件系统的例子来举例说明了组合模式的用途。在这个例子中,文件和目录都执行相同的接口,这是组合模式的关键。通过执行相同的接口,你就可以用相同的方式对待文件和目录,从而实现将文件或者目录储存为目录的子级元素。

例子

Component
为组合中的对象声明接口。
在适当的情况下,实现所有类共有接口的缺省行为。
声明一个接口用于访问和管理Component的子组件。

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
import java.util.List;

public abstract class Employer {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public abstract void add(Employer employer);

public abstract void delete(Employer employer);

public List employers;

public void printInfo(){
System.out.println(name);
}
public List getEmployers(){
return this.employers;
}
}

Leaf
在组合中表示叶节点对象,叶节点没有子节点。
在组合中定义节点对象的行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Programer extends Employer {
public Programer(String name) {
setName(name);
employers=null;//程序员,表示没有下属了
}

@Override
public void add(Employer employer) {

}

@Override
public void delete(Employer employer) {

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ProjectAssistant extends Employer {
public ProjectAssistant(String name) {
setName(name);
employers=null;//项目助理,表示没有下属了
}

@Override
public void add(Employer employer) {

}

@Override
public void delete(Employer employer) {

}
}

Composite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.ArrayList;

public class ProjectManager extends Employer {
public ProjectManager(String name) {
setName(name);
employers = new ArrayList();
}

@Override
public void add(Employer employer) {
employers.add(employer);
}

@Override
public void delete(Employer employer) {
employers.remove(employer);
}
}

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.List;

public class Test {
public static void main(String[] args) {
Employer pm = new ProjectManager("项目经理");
Employer pa = new ProjectAssistant("项目助理");
Employer programer1 = new Programer("程序员1");
Employer programer2 = new Programer("程序员2");
pm.add(pa);
pm.add(programer1);
pm.add(programer2);
List ems = pm.getEmployers();
for (Object em :ems){
System.out.println(((Employer) em).getName());
}
}
}

运行结果

1
2
3
项目助理
程序员1
程序员2

行为型模式-访问者模式

维基百科

访问者模式

访问者模式是一种将算法与对象结构分离的软件设计模式。

这个模式的基本想法如下:首先我们拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个accept方法用来接受访问者对象;访问者是一个接口,它拥有一个visit方法,这个方法对访问到的对象结构中不同类型的元素作出不同的反应;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施accept方法,在每一个元素的accept方法中回调访问者的visit方法,从而使访问者得以处理对象结构的每一个元素。我们可以针对对象结构设计不同的实在的访问者类来完成不同的操作。

访问者模式使得我们可以在传统的单分派语言(如Smalltalk、Java和C++)中模拟双分派技术。对于支持多分派的语言(如CLOS),访问者模式已经内置于语言特性之中了,从而不再重要。

Java

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
interface Visitor {
void visit(Wheel wheel);
void visit(Engine engine);
void visit(Body body);
void visit(Car car);
}

class Wheel {
private String name;
Wheel(String name) {
this.name = name;
}
String getName() {
return this.name;
}
void accept(Visitor visitor) {
visitor.visit(this);
}
}

class Engine {
void accept(Visitor visitor) {
visitor.visit(this);
}
}

class Body {
void accept(Visitor visitor) {
visitor.visit(this);
}
}

class Car {
private Engine engine = new Engine();
private Body body = new Body();
private Wheel[] wheels
= { new Wheel("front left"), new Wheel("front right"),
new Wheel("back left") , new Wheel("back right") };
void accept(Visitor visitor) {
visitor.visit(this);
engine.accept(visitor);
body.accept(visitor);
for (int i = 0; i < wheels.length; ++ i)
wheels[i].accept(visitor);
}
}

class PrintVisitor implements Visitor {
public void visit(Wheel wheel) {
System.out.println("Visiting " + wheel.getName()
+ " wheel");
}
public void visit(Engine engine) {
System.out.println("Visiting engine");
}
public void visit(Body body) {
System.out.println("Visiting body");
}
public void visit(Car car) {
System.out.println("Visiting car");
}
}

public class VisitorDemo {
static public void main(String[] args) {
Car car = new Car();
Visitor visitor = new PrintVisitor();
car.accept(visitor);
}
}

运行结果:

1
2
3
4
5
6
7
Visiting car
Visiting engine
Visiting body
Visiting front left wheel
Visiting front right wheel
Visiting back left wheel
Visiting back right wheel

行为型模式-模板方法

维基百科

模板方法

模板方法模型是一种行为设计模型。模板方法是一个定义在父类别的方法,在模板方法中会呼叫多个定义在父类别的其他方法,而这些方法有可能只是抽象方法并没有实作,模板方法仅决定这些抽象方法的执行顺序,这些抽象方法的实作由子类别负责,并且子类别不允许覆写模板方法。

用法

模板方法模式多用在:

  • 某些类别的算法中,实做了相同的方法,造成程式码的重复。
  • 控制子类别必须遵守的一些事项。
  • Java

    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
    /**
    * An abstract class that is common to several games in
    * which players play against the others, but only one is
    * playing at a given time.
    */

    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();
    }
    }

    //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. */

    // ...

    }

    public class Player {
    public static void main(String[] args) {
    Game chessGame = new Chess();
    chessGame.initializeGame();
    chessGame.playOneGame(1); //call template method
    }
    }

例子

AbstractClass
定义抽象的原语操作(primitiveoperation),具体的子类将重定义它们以实现一个算法的各步骤。
实现一个模板方法,定义一个算法的骨架。
该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。

1
2
3
4
5
6
7
8
9
public abstract class Template {
public abstract void print();
public void update(){
System.out.println("开始打印---");
for (int i=0;i<10;i++){
print();
}
}
}

ConcreteClass
实现原语操作以完成算法中与特定子类相关的步骤。

1
2
3
4
5
6
public class TemplateConcrete extends Template {
@Override
public void print() {
System.out.println("这是子类的实现");
}
}

Test

1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
Template temp = new TemplateConcrete();
temp.update();
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
开始打印---
这是子类的实现
这是子类的实现
这是子类的实现
这是子类的实现
这是子类的实现
这是子类的实现
这是子类的实现
这是子类的实现
这是子类的实现
这是子类的实现

行为型模式-策略模式

维基百科

策略模式

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
策略模式:

  • 定义了一族算法(业务规则);
  • 封装了每个算法;
  • 这族的算法可互换代替(interchangeable)。

Java

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
//StrategyExample test application

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();

}

}

// The classes that implement a concrete strategy should implement this

// The context class uses this to call the concrete strategy
interface Strategy {

void execute();

}

// 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()");
}

}

// 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
Called FirstStrategy.execute()
Called SecondStrategy.execute()
Called ThirdStrategy.execute()

行为型模式-状态模式

百度百科

状态模式

(State Pattern)是设计模式的一种,属于行为模式。
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类

定义

(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

意图

允许一个对象在其内部状态改变时改变它的行为

适用场景

  1. 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  2. 一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。

例子

State
定义一个接口以封装与Context的一个特定状态相关的行为。

1
2
3
public interface Weather {
String getWeather();
}

Context
定义客户感兴趣的接口。
维护一个ConcreteState子类的实例,这个实例定义当前状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Context {
private Weather weather;

public Weather getWeather() {
return weather;
}

public void setWeather(Weather weather) {
this.weather = weather;
}

public String weatherMessage(){
return weather.getWeather();
}
}

ConcreteStatesubclasses
每一子类实现一个与Context的一个状态相关的行为。

1
2
3
4
5
6
public class Rain implements Weather {
@Override
public String getWeather() {
return "下雨";
}
}
1
2
3
4
5
6
public class Sunshine implements Weather {
@Override
public String getWeather() {
return "阳光";
}
}

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Test {
public static void main(String[] args) {
Context ctx1 = new Context();
ctx1.setWeather(new Sunshine());
System.out.println(ctx1.weatherMessage());

System.out.println("=================");

Context ctx2 = new Context();
ctx2.setWeather(new Rain());
System.out.println(ctx2.weatherMessage());
}
}

运行结果:

1
2
3
阳光
=================
下雨

行为型模式-观察者模式

维基百科

观察者模式

观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。

参与类别

参与本模式的各类别列出如下。成员函式以模拟的方式列出。

抽象目标类别

此抽象类别提供一个界面让观察者进行添附与解附作业。此类别内有个不公开的观察者串炼,并透过下列函式(方法)进行作业

  • 添附(Attach):新增观察者到串炼内,以追踪目标对象的变化。
  • 解附(Detach):将已经存在的观察者从串炼中移除。
  • 通知(Notify):利用观察者所提供的更新函式来通知此目标已经产生变化。

添附函式包涵了一个观察者对象参数。也许是观察者类别的虚拟函式(即更新函式),或是在非面向对象的设定中所使用的函式指标(更广泛来讲,函式子或是函式对象)。

目标类别

此类别提供了观察者欲追踪的状态。也利用其源类别(例如前述的抽象目标类别)所提供的方法,来通知所有的观察者其状态已经更新。此类别拥有以下函式

  • 取得状态(GetState):回传该目标对象的状态。

抽象观察者界面

抽象观察者类别是一个必须被实做的抽象类别。这个类别定义了所有观察者都拥有的更新用界面,此界面是用来接收目标类别所发出的更新通知。此类别含有以下函式

  • 更新(Update):会被实做的一个抽象(虚拟)函式。

观察者类别

这个类别含有指向目标类别的参考(reference),以接收来自目标类别的更新状态。此类别含有以下函式

  • 更新(Update):是前述抽象函式的实做。当这个函式被目标对象呼叫时,观察者对象将会呼叫目标对象的取得状态函式,来其所拥有的更新目标对象资讯。

每个观察者类别都要实做它自己的更新函式,以应对状态更新的情形。

当目标对象改变时,会通过呼叫它自己的通知函式来将通知送给每一个观察者对象,这个通知函式则会去呼叫已经添附在串炼内的观察者更新函式。通知与更新函式可能会有一些参数,好指明是目前目标对象内的何种改变。这么作将可增进观察者的效率(只更新那些改变部分的状态)。

用途

  • 当抽象个体有两个互相依赖的层面时。封装这些层面在单独的对象内将可允许程序员单独地去变更与重复使用这些对象,而不会产生两者之间交互的问题。
  • 当其中一个对象的变更会影响其他对象,却又不知道多少对象必须被同时变更时。
  • 当对象应该有能力通知其他对象,又不应该知道其他对象的实做细节时。

观察者模式通常与 MVC 范式有关系。在 MVC 中,观察者模式被用来降低 model 与 view 的耦合程度。一般而言, model 的改变会触发通知其他身为观察者的 model 。而这些 model 实际上是 view 。 Java Swing 就是个范例,示意了 model 预期会透过 PropertyChangeNotification 架构以送出改变的通知给其他 view 。 Model 类别是 Java bean 类别的一员,并拥有与上述目标类别同样的行为。 View 类别则系结了一些 GUI 中的可视元素,并拥有与上述观察者类别同样的行为。当应用程序在执行时。使用者将因 view 做出相应的更新而看见 model 所产生的变更。

例子

Subject(目标)
目标知道它的观察者。可以有任意多个观察者观察同一个目标。
提供注册和删除观察者对象的接口。

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
import java.util.ArrayList;
import java.util.List;

public abstract class Citizen {
List pols;
private String help = "normal";

public String getHelp() {
return help;
}

public void setHelp(String help) {
this.help = help;
}
abstract void sendMessage(String help);

public void setPoliceman(){
this.pols = new ArrayList();
}
public void register(Policeman pol){
this.pols.add(pol);
}
public void unRegister(Policeman pol){
this.pols.remove(pol);
}
}

Observer(观察者)
为那些在目标发生改变时需获得通知的对象定义一个更新接口。

1
2
3
public interface Policeman {
void action(Citizen ci);
}

ConcreteSubject(具体目标)
将有关状态存入各ConcreteObserver对象。
当它的状态发生改变时,向它的各个观察者发出通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class HuangPuCitizen extends Citizen {
public HuangPuCitizen(Policeman pol){
setPoliceman();
register(pol);
}

@Override
void sendMessage(String help) {
setHelp(help);
for(int i=0;i<pols.size();i++){
Policeman pol = (Policeman) pols.get(i);
//通知警察行动
pol.action(this);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TianHeCitizen extends Citizen {
public TianHeCitizen(Policeman pol){
setPoliceman();
register(pol);
}

@Override
void sendMessage(String help) {
setHelp(help);
for(int i=0;i<pols.size();i++){
Policeman pol = (Policeman) pols.get(i);
//通知警察行动
pol.action(this);
}
}
}

ConcreteObserver(具体观察者)
维护一个指向ConcreteSubject对象的引用。
存储有关状态,这些状态应与目标的状态保持一致。
实现Observer的更新接口并使自身状态与目标的状态保持一致

1
2
3
4
5
6
7
8
9
10
11
12
public class HuangPuPoliceman implements Policeman {
@Override
public void action(Citizen ci) {
String help = ci.getHelp();
if (help.equals("normal")){
System.out.println("一切正常,不用出动");
}
if(help.equals("unnormal")){
System.out.println("有犯罪行为,黄埔警察出动");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class TianHePoliceman implements Policeman {
@Override
public void action(Citizen ci) {
String help = ci.getHelp();
if (help.equals("normal")){
System.out.println("一切正常,不用出动");
}
if(help.equals("unnormal")){
System.out.println("有犯罪行为,天河警察出动");
}
}
}

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) {
Policeman hpPol = new HuangPuPoliceman();
Policeman thPol = new TianHePoliceman();

Citizen citizen = new HuangPuCitizen(hpPol);
citizen.sendMessage("unnormal");
citizen.sendMessage("normal");
System.out.println("======================");
Citizen citizen1 = new TianHeCitizen(thPol);
citizen1.sendMessage("normal");
citizen1.sendMessage("unnormal");
}
}

运行结果:

1
2
3
4
5
有犯罪行为,黄埔警察出动
一切正常,不用出动
======================
一切正常,不用出动
有犯罪行为,天河警察出动

行为型模式-中介者模式

维基百科

中介者模式

在软件工程领域,中介者模式定义了一个中介者对象,该对象封装了系统中对象间的交互方式。 由于它可以在运行时改变程序的行为,这种模式是一种行为型模式 。

通常程序由大量的类组成,这些类中包含程序的逻辑和运算。 然而,当开发者将更多的类加入到程序中之后,类间交互关系可能变得更为复杂,这会使得代码变得更加难以阅读和维护,尤其是在重构的时候。 此外,程序将会变得难以修改,因为对其所做的任何修改都有可能影响到其它几个类中的代码。

在中介者模式中,对象间的通信过程被封装在一个中介者(调解人)对象之中。 对象之间不再直接交互,而是通过调解人进行交互。 这么做可以减少可交互对象间的依赖,从而降低耦合。

概述

中介者模式是23个周知模式( 即GoF设计模式)中的一个,GoF设计模式旨在提供重复出现的设计问题的解决方案,以编写灵活和可复用的面向对象软件。也就是说,使对象更加易于实现、修改、测试和复用。

中介者设计模式可以解决什么问题?

  • 避免一组相互交互的对象之间出现紧耦合。
  • 能够独立地改变一组对象之间的交互关系而不影响其他对象。

使用直接逐个访问并更新彼此的方式进行对象间的交互灵活性低,因为这种方式使对象彼此间紧密耦合,导致不可能单独修改类间交互关系本身,而不影响关系中进行交互的类。并且这种方式会令对象变得无法复用,并且难以测试。

由于紧耦合的对象过多了解其他对象的内部细节,这种对象难以实现、修改、测试以及复用。

中介者模式如何解决上述问题?

  • 定义一个独立的中介者(调解员)的对象,封装一组对象之间的交互关系。
  • 对象将自己的交互委托给中介者执行,避免直接与其他对象进行交互。

对象利用中介者对象与其他对象进行间接交互,中介者对象负责控制和协调交互关系,这么做可使得对象间松耦合。这些对象只访问中介者,不了解其他对象的细节。

定义

中介者模式是为了“定义一个封装了对象间交互关系的对象”。这种方式避免了显式调用其他类,促进了类间的松耦合,并且使得类间交互关系本身可以单独修改。客户类可以使用中介者向其他客户类发送信息,并且通过中介者引发的事件收到信息。

Java

在以下示例中,一个中介者对象控制了三个互相交互的按钮的状态,为此它有设置状态的三个方法:book(), view() 和 search()。 当相应的按钮被激活时,对应的方法通过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
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

//Colleague interface
interface Command {
void execute();
}

//Abstract Mediator
interface Mediator {
void book();
void view();
void search();
void registerView(BtnView v);
void registerSearch(BtnSearch s);
void registerBook(BtnBook b);
void registerDisplay(LblDisplay d);
}

//Concrete mediator
class ParticipantMediator implements Mediator {

BtnView btnView;
BtnSearch btnSearch;
BtnBook btnBook;
LblDisplay show;

//....
public void registerView(BtnView v) {
btnView = v;
}

public void registerSearch(BtnSearch s) {
btnSearch = s;
}

public void registerBook(BtnBook b) {
btnBook = b;
}

public void registerDisplay(LblDisplay d) {
show = d;
}

public void book() {
btnBook.setEnabled(false);
btnView.setEnabled(true);
btnSearch.setEnabled(true);
show.setText("booking...");
}

public void view() {
btnView.setEnabled(false);
btnSearch.setEnabled(true);
btnBook.setEnabled(true);
show.setText("viewing...");
}

public void search() {
btnSearch.setEnabled(false);
btnView.setEnabled(true);
btnBook.setEnabled(true);
show.setText("searching...");
}

}

//A concrete colleague
class BtnView extends JButton implements Command {

Mediator med;

BtnView(ActionListener al, Mediator m) {
super("View");
addActionListener(al);
med = m;
med.registerView(this);
}

public void execute() {
med.view();
}

}

//A concrete colleague
class BtnSearch extends JButton implements Command {

Mediator med;

BtnSearch(ActionListener al, Mediator m) {
super("Search");
addActionListener(al);
med = m;
med.registerSearch(this);
}

public void execute() {
med.search();
}

}

//A concrete colleague
class BtnBook extends JButton implements Command {

Mediator med;

BtnBook(ActionListener al, Mediator m) {
super("Book");
addActionListener(al);
med = m;
med.registerBook(this);
}

public void execute() {
med.book();
}

}

class LblDisplay extends JLabel {

Mediator med;

LblDisplay(Mediator m) {
super("Just start...");
med = m;
med.registerDisplay(this);
setFont(new Font("Arial", Font.BOLD, 24));
}

}

class MediatorDemo extends JFrame implements ActionListener {

Mediator med = new ParticipantMediator();

MediatorDemo() {
JPanel p = new JPanel();
p.add(new BtnView(this, med));
p.add(new BtnBook(this, med));
p.add(new BtnSearch(this, med));
getContentPane().add(new LblDisplay(med), "North");
getContentPane().add(p, "South");
setSize(400, 200);
setVisible(true);
}

public void actionPerformed(ActionEvent ae) {
Command comd = (Command) ae.getSource();
comd.execute();
}

public static void main(String[] args) {
new MediatorDemo();
}

}

例子

Colleagueclass

1
2
3
4
5
public class Colleague {
public void action(){

}
}
1
2
3
4
5
6
public class ColleagueA extends Colleague{
@Override
public void action() {
System.out.println("普通员工努力工作");
}
}
1
2
3
4
5
6
public class ColleagueB extends Colleague {
@Override
public void action() {
System.out.println("前台注意了");
}
}

Mediator

1
2
3
public abstract class Mediator {
public abstract void notice(String content);
}

ConcreteMediator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ConcreateMedator extends Mediator {
private ColleagueA ca;
private ColleagueB cb;

public ConcreateMedator() {
ca=new ColleagueA();
cb=new ColleagueB();
}

@Override
public void notice(String content) {
if(content.equals("boss")){
ca.action();
}
if(content.equals("client")){
cb.action();
}
}
}

Test

1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Mediator med = new ConcreateMedator();
med.notice("boss");
med.notice("client");
}
}

运行结果:

1
2
普通员工努力工作
前台注意了

行为型模式-迭代器模式

维基百科

迭代器模式

在 面向对象编程里,迭代器模式是一种设计模式,是一种最简单也最常见的设计模式。它可以让用户透过特定的接口巡访容器中的每一个元素而不用了解底层的实现。

此外,也可以实现特定目的版本的迭代器。

接口

《设计模式》建议合理的接口该要有:

1
2
3
4
5
6
7
public interface Iterator
{
public Object First();
public Object Next();
public boolean isDone();
public Object CurrentItem();
}

Java

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
interface Iterator{
Object First();
Object Next();
boolean IsDone();
Object CurrentItem();
}

abstract class Aggregate{
abstract Iterator CreateIterator();
}

class ConcreteIterator implements Iterator{
private List<Object> list = new ArrayList<Object>();
private int curr=0;
public ConcreteIterator(List<Object> list){
this.list = list;
}

public Object First(){
return list.get(0);
}

public Object Next(){
Object ret = null;
curr++;
if(curr < list.size()){
ret = list.get(curr);
}
return ret;
}

public boolean IsDone(){
return curr>=list.size()?true:false;
}

public Object CurrentItem(){
return list.get(curr);
}
}

class ConcreteAggregate extends Aggregate{
private List<Object> list = new ArrayList<Object>();
public ConcreteAggregate(List<Object> list){
this.list = list;
}
public Iterator CreateIterator(){
return new ConcreteIterator(list);
}
}

class client{
public static void main(String[] args){
List<Object> list = new ArrayList<Object>();
list.add("miner");
list.add("any");
Aggregate agg = new ConcreteAggregate(list);
Iterator iterator = agg.CreateIterator();
iterator.First();
while(!iterator.IsDone()){
System.out.println(iterator.CurrentItem());
iterator.Next();
}
}
}

例子

Aggregate
聚合定义创建相应迭代器对象的接口。

1
2
3
4
5
6
public interface List {
Iterator iterator();
Object get(int index);
int getSize();
void add(Object obj);
}

Iterator
迭代器定义访问和遍历元素的接口。

1
2
3
4
5
6
public interface Iterator {
Object next();
void first();
void last();
boolean hasNext();
}

ConcreteIterator
具有迭代器实现迭代器接口。
对该聚合遍历时跟踪当前位置。

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
public class IteratorImpl implements Iterator {
private List list;
private int index;

public IteratorImpl(List list) {
this.list = list;
index=0;
}

@Override
public Object next() {
Object obj = list.get(index);
index++;
return obj;
}

@Override
public void first() {
index=0;
}

@Override
public void last() {
index=list.getSize();
}

@Override
public boolean hasNext() {
return index<list.getSize();
}
}

ConcreteAggregate
具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例

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
public class ListImpl implements List {
private Object[] list;
private int index;
private int size;

public ListImpl() {
index=0;
size=0;
list = new Object[100];
}

@Override
public Iterator iterator() {
return new IteratorImpl(this);
}

@Override
public Object get(int index) {
return list[index];
}

@Override
public int getSize() {
return this.size;
}

@Override
public void add(Object obj) {
list[index++]=obj;
size++;
}
}

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
public static void main(String[] args) {
List list = new ListImpl();
list.add("a");
list.add("b");
list.add("c");
//第一种迭代方式
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("=============");
//第二种迭代方式
for(int i=0;i<list.getSize();i++){
System.out.println(list.get(i));
}
}
}

运行结果:

1
2
3
4
5
6
7
a
b
c
=============
a
b
c