设计模式教程(3) - 对象行为型模式

策略模式

定义

策略模式定义了算法家族并将它们封装起来,让他们之间可以互相替换,此模式让算法变化而不会影响到使用算法的客户

适用场景

商场经常会进行各式各样的促销活动,这就要求收银软件需要按照不同的促销方式来对顾客的最终费用进行计算,这里的促销方式其实就是各类打折算法,并且这些算法之间还可以互相替换而不影响到使用这些算法的客户端也就是前面说的收银软件。

结构图

代码示例

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 abstract class Strategy {
public abstract void AlgorithmInterfaace();
}
class ConcreteStrategyA extends Strategy{
public void AlgorithmInterfaace() {
System.out.println("具体策略A");
}
}
class ConcreteStrategyB extends Strategy{
public void AlgorithmInterfaace() {
System.out.println("具体策略B");
}
}
class ConcreteStrategyC extends Strategy{
public void AlgorithmInterfaace() {
System.out.println("具体策略C");
}
}
class Context{
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public void contextInterface(){
strategy.AlgorithmInterfaace();
}
}

模板方法模式

定义

定义一个操作中的算法的骨架,而将一些不走延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤

适用场景

模板方法通过把不变行为搬移到超类,去除子类中重复代码来体现它的优势。模板方法提供了一个很好的代码复用平台,因为有时候,我们会遇到由一系列步骤构成的过程需要执行。这些过程从高层次上看是相同,但有些步骤的实现可能不同。这时候,我们通常就应该要考虑用模板方法模式

结构图

代码示例

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
abstract class Abstract{
public abstract void promitiveOperation1();
public abstract void promitiveOperation2();
public void templateMethod(){
promitiveOperation1();
promitiveOperation2();
System.out.println("方法调用完毕");
}
}
class ConcreteClassA extends Abstract{
@Override
public void promitiveOperation1() {
System.out.println("具体类A的方法1重写");
}
@Override
public void promitiveOperation2() {
System.out.println("具体类A的方法2重写");
}
}
class ConcreteClassB extends Abstract{
@Override
public void promitiveOperation1() {
System.out.println("具体类B的方法1重写");
}
@Override
public void promitiveOperation2() {
System.out.println("具体类B的方法2重写");
}
}

观察者模式

定义

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己

适用场景

当一个对象的改变需要同时改变其他对象的时候,且该对象并不知道具有有多少对象有待改变时,应该适用观察者模式

结构图

代码示例

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
/**
* Subject类,可翻译为主题或者抽象通知者,一般用一个抽象类或者一个接口实现。
* 它把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任何数量的观察者,抽象主题提供
* @author jiangrenjie
*
*/
abstract class Subject{
private List<Observer> observers = new ArrayList<>();
public void attach(Observer o){
observers.add(o);
}
public void Detach(Observer o){
observers.remove(o);
}
public void inform(){
for(Observer o : observers){
o.update();
}
}
}
class ConcreteSubject extends Subject{
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
/**
* Observer称为抽象观察者,为所有的具体观察者定义一个接口
* 在得到主题的通知时更新自己,这个接口叫做更新接口
* @author jiangrenjie
*
*/
abstract class Observer{
public abstract void update();
}
class ConcreteObserver extends Observer{
private String name;
private String observerState;
private ConcreteSubject subejct;
public ConcreteObserver(String name, ConcreteSubject subject){
this.name = name;
this.subejct = subject;
}
public String getObserverState() {
return observerState;
}
public void setObserverState(String observerState) {
this.observerState = observerState;
}
@Override
public void update() {
observerState = subejct.getSubjectState();
System.out.println("观察者:"+name+"的新状态是:"+observerState);
}
}
public class ObserverTest {
public static void main(String[] args) {
ConcreteSubject s = new ConcreteSubject();
s.setSubjectState("ABC");
s.attach(new ConcreteObserver("X", s));
s.attach(new ConcreteObserver("Y", s));
s.attach(new ConcreteObserver("Z",s));
s.inform();
}
}

迭代器模式

定义

提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示

适用场景

当需要对一个聚集对象里面的每个元素都进行遍历的时候就可以考虑适用迭代器模式

结构图

代码示例

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
interface Collection{
public Iterator iterator();
//获取元素
public Object get(int i);
//获取集合的大小
public int Size();
}
class MyCollection implements Collection{
private String[] strings = {"a", "b", "c", "d", "e"};
@Override
public Iterator iterator() {
return new MyIterator(this);
}
@Override
public Object get(int i) {
return strings[i];
}
@Override
public int Size() {
return strings.length;
}
}
interface Iterator{
//前移
public Object previous();
//后移
public Object next();
public boolean hasNext();
//取得第一个元素
public Object first();
}
class MyIterator implements Iterator{
private Collection collection;
private int ops = -1;
public MyIterator(Collection collection){
this.collection = collection;
}
@Override
public Object previous() {
if(ops > 0){
ops--;
}
return collection.get(ops);
}
@Override
public Object next() {
if(ops < (collection.Size()-1)){
ops++;
}
return collection.get(ops);
}
@Override
public boolean hasNext() {
if(ops < (collection.Size()-1)){
return true;
}else{
return false;
}
}
@Override
public Object first() {
return collection.get(0);
}
}
public class IteratorTest {
public static void main(String[] args) {
Collection collection = new MyCollection();
Iterator it = collection.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}

责任链模式

定义

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

适用场景

当客户提交一个请求时,请求时沿链传递直至有一个ConcreteHandler对象负责处理它,这样使得接受者和发送者都没有对方明确的信息,且链中的对象自己也并不知道链的结构,职责链可简化对象的相互连接,他们仅需保持一个指向其后继者的引用,而不需保持他所有的候选接受者的引用

结构图

代码示例

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
abstract class Handler{
protected Handler successor;
public void SetSuccessor(Handler successor){
this.successor = successor;
}
public abstract void handRequest(int request);
}
class ConcreteHandlerA extends Handler{
@Override
public void handRequest(int request) {
if(request >=0 && request < 10){
System.out.println("当request在0-10之间(包含0)时处理该请求,当前请求参数为:"+request+" - "+this.getClass().getName());
}else if(successor != null){
successor.handRequest(request);
}
}
}
class ConcreteHandlerB extends Handler{
@Override
public void handRequest(int request) {
if(request >= 10 && request < 20){
System.out.println("当request在10-20之间(包含10)时处理该请求,当前请求参数为:"+request+" - "+this.getClass().getName());
}else if(successor != null){
successor.handRequest(request);
}
}
}
class ConcreteHandlerC extends Handler{
@Override
public void handRequest(int request) {
if(request >= 20){
System.out.println("当request大于等于20时处理该请求,当前请求参数为:"+request+" - "+this.getClass().getName());
}else if(successor != null){
successor.handRequest(request);
}
}
}
public class ChainOfResponsibilityTest {
public static void main(String[] args) {
Handler a = new ConcreteHandlerA();
Handler b = new ConcreteHandlerB();
Handler c = new ConcreteHandlerC();
a.SetSuccessor(b);
b.SetSuccessor(c);
int[] requests = {1, 5, 10, 15, 18, 29, 30, 50};
for(int request : requests){
a.handRequest(request);
}
}
}

命令模式

定义

将一个请求封装为一个对象,从而使你可用不用的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可测销的操作

适用场景

当需要将请求一个操作对象但并不需要知道如何执行这个操作对象时可以使用命令模式

优点

  1. 命令模式比较容易设置一个命令队列
  2. 可以对命令队列的相关操作进行日志记录
  3. 命令对象可以对命令调用指令进行过滤,可否决一部分调用请求
  4. 可以很容易的实现对请求的撤销和重做
  5. 实现了命令类与具体命令类的解耦,符合“开闭原则”

结构图

代码示例

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
abstract class Receiver{
public abstract void action();
}
class ConcreteReceiverA extends Receiver{
@Override
public void action() {
System.out.println("具体命令接收者A的具体请求");
}
}
class ConcreteReceiverB extends Receiver{
@Override
public void action() {
System.out.println("具体命令接收者B的具体请求");
}
}
abstract class Command{
protected Receiver receiver;
public Command(Receiver receiver){
this.receiver = receiver;
}
public abstract void Execute();
}
class ConcreteCommandA extends Command{
public ConcreteCommandA(ConcreteReceiverA receiver){
super(receiver);
}
@Override
public void Execute() {
receiver.action();
}
}
class ConcreteCommandB extends Command{
public ConcreteCommandB(ConcreteReceiverB receiver) {
super(receiver);
}
@Override
public void Execute() {
receiver.action();
}
}
class Invoker{
private List<Command> commands = new ArrayList<Command>();
public void add(Command command){
commands.add(command);
}
public void ExecuteCommand(){
for(Command command : commands){
command.Execute();
}
}
}
public class CommandTest {
public static void main(String[] args) {
Receiver b = new ConcreteReceiverB();
Command commandA = new ConcreteCommandA(new ConcreteReceiverA());
Command commandB = new ConcreteCommandB(new ConcreteReceiverB());
Invoker i = new Invoker();
i.add(commandA);
i.add(commandB);
i.ExecuteCommand();
}
}

备忘录模式

定义

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

适用场景

备忘录模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator可以根据保存的Memento信息还原到前一状态

结构图

代码示例

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
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 show(){
System.out.println("state:"+ state);
}
}
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;
}
}
class Caretaker{
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class MementoTest {
public static void main(String[] args) {
Originator o = new Originator();
o.setState("on");
o.show();
Caretaker c = new Caretaker();
c.setMemento(o.createMemento());
o.setState("off");
o.show();
o.SetMemento(c.getMemento());
o.show();
}
}

状态模式

定义

当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了起来

适用场景

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

状态模式主要是为了相处庞大的条件分支语句,大的分支判断会使得他们难以修改和扩展。状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖

当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑适用状态模式

结构图

代码示例

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
abstract class State{
public abstract void handle(Context context);
}
class ConcreteStateA extends State{
@Override
public void handle(Context context) {
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State{
@Override
public void handle(Context context) {
context.setState(new ConcreteStateC());
}
}
class ConcreteStateC extends State{
@Override
public void handle(Context context) {
context.setState(new ConcreteStateA());
}
}
class Context{
private State state;
public Context(State state){
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
System.out.println("当前状态:"+state.getClass().getName());
}
public void request(){
state.handle(this);
}
}
public class StateTest {
public static void main(String[] args) {
Context c = new Context(new ConcreteStateA());
c.request();
c.request();
c.request();
c.request();
}
}

访问者模式

定义

访问者模式表示一个作用于某个对象结构中的个元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

适用场景

访问者模式的目的就是要把处理从数据结构分离出来。很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易

结构图

代码示例

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
abstract class Visitor{
public abstract void visitConcreteElementA(ConcreteElementA element);
public abstract void visitConcreteElementB(ConcreteElementB element);
}
class ConcreteVisitorA extends Visitor{
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println(element.getClass().getName()+" to be accessed by "+this.getClass().getName());
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println(element.getClass().getName()+" to be accessed by "+this.getClass().getName());
}
}
class ConcreteVisitorB extends Visitor{
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println(element.getClass().getName()+" to be accessed by "+this.getClass().getName());
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println(element.getClass().getName()+" to be accessed by "+this.getClass().getName());
}
}
abstract class Element{
public abstract void accept(Visitor visitor);
}
class ConcreteElementA extends Element{
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
public void OperationA(){
}
}
class ConcreteElementB extends Element{
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public void OperationB(){
}
}
class ObjectStructure{
private List<Element> elements = new ArrayList<>();
public void attach(Element element){
elements.add(element);
}
public void detach(Element element){
elements.remove(element);
}
public void accept(Visitor visitor){
for(Element element : elements){
element.accept(visitor);
}
}
}
public class VisitorTest {
public static void main(String[] args) {
ObjectStructure o = new ObjectStructure();
Element ea = new ConcreteElementA();
Element eb = new ConcreteElementB();
o.attach(ea);
o.attach(eb);
Visitor va = new ConcreteVisitorA();
Visitor vb = new ConcreteVisitorB();
o.accept(va);
o.accept(vb);
}
}

中介者模式

定义

中介者模式是指用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互

适用场景

中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合

结构图

代码示例

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
abstract class Mediator{
public abstract void send(String message, Colleague colleague);
}
class ConcreteMediatorA extends Mediator{
private ConcreteColleagueA ca;
private ConcreteColleagueB cb;
public ConcreteColleagueA getCa() {
return ca;
}
public void setCa(ConcreteColleagueA ca) {
this.ca = ca;
}
public ConcreteColleagueB getCb() {
return cb;
}
public void setCb(ConcreteColleagueB cb) {
this.cb = cb;
}
@Override
public void send(String message, Colleague colleague) {
if(colleague == ca){
cb.notify(message);
}else{
ca.notify(message);
}
}
}
abstract class Colleague{
protected Mediator mediator;
public Colleague(Mediator mediator){
this.mediator = mediator;
}
public abstract void send(String message);
public abstract void notify(String message);
}
class ConcreteColleagueA extends Colleague{
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
mediator.send(message, this);
}
@Override
public void notify(String message) {
System.out.println("同事A得到信息:"+message);
}
}
class ConcreteColleagueB extends Colleague{
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
mediator.send(message, this);
}
@Override
public void notify(String message) {
System.out.println("同事B得到信息:"+message);
}
}
public class MediatorTest {
public static void main(String[] args) {
ConcreteMediatorA m = new ConcreteMediatorA();
ConcreteColleagueA ca = new ConcreteColleagueA(m);
ConcreteColleagueB cb = new ConcreteColleagueB(m);
m.setCa(ca);
m.setCb(cb);
ca.send("吃饭了吗");
cb.send("吃过了");
}
}

解释器模式

定义

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子

使用场景

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

-------------本文到此结束,感谢您的阅读-------------