面向对象-设计模式-行为型

面向对象-设计模式-行为型

 

      日暮乡关何处是?烟波江上使人愁。

 

简介:面向对象-设计模式-行为型。

一、概述

何谓设计模式

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。

设计模式的好处&学习目的

1、为了代码可重用行、让代码更易被他人理解、保证代码的可靠性、使代码编写真正实现工程化;

2、设计模式便于我们维护项目,增强系统的健壮性和可扩展性;

3、设计模式还可以锻炼码农的设计思维、升华代码质量等。

二、行为型

责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式、空对象模式。

1. 责任链(Chain Of Responsibility)

Intent

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

Class Diagram

  • Handler:定义处理请求的接口,并且实现后继链(successor)

Implementation

 1 public abstract class Handler {
 2 
 3     protected Handler successor;
 4 
 5 
 6     public Handler(Handler successor) {
 7         this.successor = successor;
 8     }
 9 
10 
11     protected abstract void handleRequest(Request request);
12 }
View Code
 1 public class ConcreteHandler1 extends Handler {
 2 
 3     public ConcreteHandler1(Handler successor) {
 4         super(successor);
 5     }
 6 
 7 
 8     @Override
 9     protected void handleRequest(Request request) {
10         if (request.getType() == RequestType.TYPE1) {
11             System.out.println(request.getName() + " is handle by ConcreteHandler1");
12             return;
13         }
14         if (successor != null) {
15             successor.handleRequest(request);
16         }
17     }
18 }
View Code
 1 public class ConcreteHandler2 extends Handler {
 2 
 3     public ConcreteHandler2(Handler successor) {
 4         super(successor);
 5     }
 6 
 7 
 8     @Override
 9     protected void handleRequest(Request request) {
10         if (request.getType() == RequestType.TYPE2) {
11             System.out.println(request.getName() + " is handle by ConcreteHandler2");
12             return;
13         }
14         if (successor != null) {
15             successor.handleRequest(request);
16         }
17     }
18 }
View Code
 1 public class Request {
 2 
 3     private RequestType type;
 4     private String name;
 5 
 6 
 7     public Request(RequestType type, String name) {
 8         this.type = type;
 9         this.name = name;
10     }
11 
12 
13     public RequestType getType() {
14         return type;
15     }
16 
17 
18     public String getName() {
19         return name;
20     }
21 }
View Code
1 public enum RequestType {
2     TYPE1, TYPE2
3 }
 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4 
 5         Handler handler1 = new ConcreteHandler1(null);
 6         Handler handler2 = new ConcreteHandler2(handler1);
 7 
 8         Request request1 = new Request(RequestType.TYPE1, "request1");
 9         handler2.handleRequest(request1);
10 
11         Request request2 = new Request(RequestType.TYPE2, "request2");
12         handler2.handleRequest(request2);
13     }
14 }
View Code
1 输出:
2 request1 is handle by ConcreteHandler1
3 request2 is handle by ConcreteHandler2

2. 命令(Command)

Intent

将命令封装成对象中,具有以下作用:

  • 使用命令来参数化其它对象
  • 将命令放入队列中进行排队
  • 将命令的操作记录到日志中
  • 支持可撤销的操作

Class Diagram

  • Command:命令
  • Receiver:命令接收者,也就是命令真正的执行者
  • Invoker:通过它来调用命令
  • Client:可以设置命令与命令的接收者

Implementation

设计一个遥控器,可以控制电灯开关。

1 public interface Command {
2     void execute();
3 }
 1 public class LightOnCommand implements Command {
 2     Light light;
 3 
 4     public LightOnCommand(Light light) {
 5         this.light = light;
 6     }
 7 
 8     @Override
 9     public void execute() {
10         light.on();
11     }
12 }
View Code
 1 public class LightOffCommand implements Command {
 2     Light light;
 3 
 4     public LightOffCommand(Light light) {
 5         this.light = light;
 6     }
 7 
 8     @Override
 9     public void execute() {
10         light.off();
11     }
12 }
View Code
 1 public class Light {
 2 
 3     public void on() {
 4         System.out.println("Light is on!");
 5     }
 6 
 7     public void off() {
 8         System.out.println("Light is off!");
 9     }
10 }
View Code
 1 /**
 2  * 遥控器
 3  */
 4 public class Invoker {
 5     private Command[] onCommands;
 6     private Command[] offCommands;
 7     private final int slotNum = 7;
 8 
 9     public Invoker() {
10         this.onCommands = new Command[slotNum];
11         this.offCommands = new Command[slotNum];
12     }
13 
14     public void setOnCommand(Command command, int slot) {
15         onCommands[slot] = command;
16     }
17 
18     public void setOffCommand(Command command, int slot) {
19         offCommands[slot] = command;
20     }
21 
22     public void onButtonWasPushed(int slot) {
23         onCommands[slot].execute();
24     }
25 
26     public void offButtonWasPushed(int slot) {
27         offCommands[slot].execute();
28     }
29 }
View Code
 1 public class Client {
 2     public static void main(String[] args) {
 3         Invoker invoker = new Invoker();
 4         Light light = new Light();
 5         Command lightOnCommand = new LightOnCommand(light);
 6         Command lightOffCommand = new LightOffCommand(light);
 7         invoker.setOnCommand(lightOnCommand, 0);
 8         invoker.setOffCommand(lightOffCommand, 0);
 9         invoker.onButtonWasPushed(0);
10         invoker.offButtonWasPushed(0);
11     }
12 }

3. 解释器(Interpreter)

Intent

为语言创建解释器,通常由语言的语法和语法分析来定义。

Class Diagram

  • TerminalExpression:终结符表达式,每个终结符都需要一个 TerminalExpression。
  • Context:上下文,包含解释器之外的一些全局信息。

Implementation

以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一颗解析树,用来检验一个文本是否满足解析树定义的规则。

例如一颗解析树为 D And (A Or (B C)),文本 "D A" 满足该解析树定义的规则。

这里的 Context 指的是 String。

1 public abstract class Expression {
2     public abstract boolean interpret(String str);
3 }
 1 public class TerminalExpression extends Expression {
 2 
 3     private String literal = null;
 4 
 5     public TerminalExpression(String str) {
 6         literal = str;
 7     }
 8 
 9     public boolean interpret(String str) {
10         StringTokenizer st = new StringTokenizer(str);
11         while (st.hasMoreTokens()) {
12             String test = st.nextToken();
13             if (test.equals(literal)) {
14                 return true;
15             }
16         }
17         return false;
18     }
19 }
View Code
 1 public class AndExpression extends Expression {
 2 
 3     private Expression expression1 = null;
 4     private Expression expression2 = null;
 5 
 6     public AndExpression(Expression expression1, Expression expression2) {
 7         this.expression1 = expression1;
 8         this.expression2 = expression2;
 9     }
10 
11     public boolean interpret(String str) {
12         return expression1.interpret(str) && expression2.interpret(str);
13     }
14 }
View Code
 1 public class OrExpression extends Expression {
 2     private Expression expression1 = null;
 3     private Expression expression2 = null;
 4 
 5     public OrExpression(Expression expression1, Expression expression2) {
 6         this.expression1 = expression1;
 7         this.expression2 = expression2;
 8     }
 9 
10     public boolean interpret(String str) {
11         return expression1.interpret(str) || expression2.interpret(str);
12     }
13 }
View Code
 1 public class Client {
 2 
 3     /**
 4      * 构建解析树
 5      */
 6     public static Expression buildInterpreterTree() {
 7         // Literal
 8         Expression terminal1 = new TerminalExpression("A");
 9         Expression terminal2 = new TerminalExpression("B");
10         Expression terminal3 = new TerminalExpression("C");
11         Expression terminal4 = new TerminalExpression("D");
12         // B C
13         Expression alternation1 = new OrExpression(terminal2, terminal3);
14         // A Or (B C)
15         Expression alternation2 = new OrExpression(terminal1, alternation1);
16         // D And (A Or (B C))
17         return new AndExpression(terminal4, alternation2);
18     }
19 
20     public static void main(String[] args) {
21         Expression define = buildInterpreterTree();
22         String context1 = "D A";
23         String context2 = "A B";
24         System.out.println(define.interpret(context1));  // true
25         System.out.println(define.interpret(context2));  // false
26     }
27 }
View Code

4. 迭代器(Iterator)

Intent

提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。

Class Diagram

  • Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator;
  • Iterator 主要定义了 hasNext() 和 next() 方法;
  • Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。

Implementation

1 public interface Aggregate {
2     Iterator createIterator();
3 }
 1 public class ConcreteAggregate implements Aggregate {
 2 
 3     private Integer[] items;
 4 
 5     public ConcreteAggregate() {
 6         items = new Integer[10];
 7         for (int i = 0; i < items.length; i++) {
 8             items[i] = i;
 9         }
10     }
11 
12     @Override
13     public Iterator createIterator() {
14         return new ConcreteIterator<Integer>(items);
15     }
16 }
View Code
1 public interface Iterator<Item> {
2     Item next();
3     boolean hasNext();
4 }
 1 public class ConcreteIterator<Item> implements Iterator {
 2 
 3     private Item[] items;
 4     private int position = 0;
 5 
 6     public ConcreteIterator(Item[] items) {
 7         this.items = items;
 8     }
 9 
10     @Override
11     public Object next() {
12         return items[position++];
13     }
14 
15     @Override
16     public boolean hasNext() {
17         return position < items.length;
18     }
19 }
View Code
1 public class Client {
2     public static void main(String[] args) {
3         Aggregate aggregate = new ConcreteAggregate();
4         Iterator<Integer> iterator = aggregate.createIterator();
5         while (iterator.hasNext()) {
6             System.out.println(iterator.next());
7         }
8     }
9 }

5. 中介者(Mediator)

Intent

集中相关对象之间复杂的沟通和控制方式。

Class Diagram

  • Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。
  • Colleague:同事,相关对象。

Implementation

Alarm(闹钟)、CoffeePot(咖啡壶)、Calendar(日历)、Sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构:

使用中介者模式可以将复杂的依赖结构变成星形结构:

1 public abstract class Colleague {
2     public abstract void onEvent(Mediator mediator);
3 }
 1 public class Alarm extends Colleague {
 2 
 3     @Override
 4     public void onEvent(Mediator mediator) {
 5         mediator.doEvent("alarm");
 6     }
 7 
 8     public void doAlarm() {
 9         System.out.println("doAlarm()");
10     }
11 }
View Code
 1 public class CoffeePot extends Colleague {
 2     @Override
 3     public void onEvent(Mediator mediator) {
 4         mediator.doEvent("coffeePot");
 5     }
 6 
 7     public void doCoffeePot() {
 8         System.out.println("doCoffeePot()");
 9     }
10 }
View Code
 1 public class Calender extends Colleague {
 2     @Override
 3     public void onEvent(Mediator mediator) {
 4         mediator.doEvent("calender");
 5     }
 6 
 7     public void doCalender() {
 8         System.out.println("doCalender()");
 9     }
10 }
View Code
 1 public class Sprinkler extends Colleague {
 2     @Override
 3     public void onEvent(Mediator mediator) {
 4         mediator.doEvent("sprinkler");
 5     }
 6 
 7     public void doSprinkler() {
 8         System.out.println("doSprinkler()");
 9     }
10 }
View Code
1 public abstract class Mediator {
2     public abstract void doEvent(String eventType);
3 }
 1 public class ConcreteMediator extends Mediator {
 2     private Alarm alarm;
 3     private CoffeePot coffeePot;
 4     private Calender calender;
 5     private Sprinkler sprinkler;
 6 
 7     public ConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calender calender, Sprinkler sprinkler) {
 8         this.alarm = alarm;
 9         this.coffeePot = coffeePot;
10         this.calender = calender;
11         this.sprinkler = sprinkler;
12     }
13 
14     @Override
15     public void doEvent(String eventType) {
16         switch (eventType) {
17             case "alarm":
18                 doAlarmEvent();
19                 break;
20             case "coffeePot":
21                 doCoffeePotEvent();
22                 break;
23             case "calender":
24                 doCalenderEvent();
25                 break;
26             default:
27                 doSprinklerEvent();
28         }
29     }
30 
31     public void doAlarmEvent() {
32         alarm.doAlarm();
33         coffeePot.doCoffeePot();
34         calender.doCalender();
35         sprinkler.doSprinkler();
36     }
37 
38     public void doCoffeePotEvent() {
39         // ...
40     }
41 
42     public void doCalenderEvent() {
43         // ...
44     }
45 
46     public void doSprinklerEvent() {
47         // ...
48     }
49 }
View Code
 1 public class Client {
 2     public static void main(String[] args) {
 3         Alarm alarm = new Alarm();
 4         CoffeePot coffeePot = new CoffeePot();
 5         Calender calender = new Calender();
 6         Sprinkler sprinkler = new Sprinkler();
 7         Mediator mediator = new ConcreteMediator(alarm, coffeePot, calender, sprinkler);
 8         // 闹钟事件到达,调用中介者就可以操作相关对象
 9         alarm.onEvent(mediator);
10     }
11 }
1 输出:
2 doAlarm()
3 doCoffeePot()
4 doCalender()
5 doSprinkler()

6. 备忘录(Memento)

Intent

在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。

Class Diagram

  • Originator:原始对象
  • Caretaker:负责保存好备忘录
  • Memento:备忘录,存储原始对象的状态。备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。

Implementation

以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。

 1 /**
 2  * Originator Interface
 3  */
 4 public interface Calculator {
 5 
 6     // Create Memento
 7     PreviousCalculationToCareTaker backupLastCalculation();
 8 
 9     // setMemento
10     void restorePreviousCalculation(PreviousCalculationToCareTaker memento);
11 
12     int getCalculationResult();
13 
14     void setFirstNumber(int firstNumber);
15 
16     void setSecondNumber(int secondNumber);
17 }
View Code
 1 /**
 2  * Originator Implementation
 3  */
 4 public class CalculatorImp implements Calculator {
 5 
 6     private int firstNumber;
 7     private int secondNumber;
 8 
 9     @Override
10     public PreviousCalculationToCareTaker backupLastCalculation() {
11         // create a memento object used for restoring two numbers
12         return new PreviousCalculationImp(firstNumber, secondNumber);
13     }
14 
15     @Override
16     public void restorePreviousCalculation(PreviousCalculationToCareTaker memento) {
17         this.firstNumber = ((PreviousCalculationToOriginator) memento).getFirstNumber();
18         this.secondNumber = ((PreviousCalculationToOriginator) memento).getSecondNumber();
19     }
20 
21     @Override
22     public int getCalculationResult() {
23         // result is adding two numbers
24         return firstNumber + secondNumber;
25     }
26 
27     @Override
28     public void setFirstNumber(int firstNumber) {
29         this.firstNumber = firstNumber;
30     }
31 
32     @Override
33     public void setSecondNumber(int secondNumber) {
34         this.secondNumber = secondNumber;
35     }
36 }
View Code
1 /**
2  * Memento Interface to Originator
3  *
4  * This interface allows the originator to restore its state
5  */
6 public interface PreviousCalculationToOriginator {
7     int getFirstNumber();
8     int getSecondNumber();
9 }
1 /**
2  *  Memento interface to CalculatorOperator (Caretaker)
3  */
4 public interface PreviousCalculationToCareTaker {
5     // no operations permitted for the caretaker
6 }
 1 /**
 2  * Memento Object Implementation
 3  * <p>
 4  * Note that this object implements both interfaces to Originator and CareTaker
 5  */
 6 public class PreviousCalculationImp implements PreviousCalculationToCareTaker,
 7         PreviousCalculationToOriginator {
 8 
 9     private int firstNumber;
10     private int secondNumber;
11 
12     public PreviousCalculationImp(int firstNumber, int secondNumber) {
13         this.firstNumber = firstNumber;
14         this.secondNumber = secondNumber;
15     }
16 
17     @Override
18     public int getFirstNumber() {
19         return firstNumber;
20     }
21 
22     @Override
23     public int getSecondNumber() {
24         return secondNumber;
25     }
26 }
View Code
 1 /**
 2  * CareTaker object
 3  */
 4 public class Client {
 5 
 6     public static void main(String[] args) {
 7         // program starts
 8         Calculator calculator = new CalculatorImp();
 9 
10         // assume user enters two numbers
11         calculator.setFirstNumber(10);
12         calculator.setSecondNumber(100);
13 
14         // find result
15         System.out.println(calculator.getCalculationResult());
16 
17         // Store result of this calculation in case of error
18         PreviousCalculationToCareTaker memento = calculator.backupLastCalculation();
19 
20         // user enters a number
21         calculator.setFirstNumber(17);
22 
23         // user enters a wrong second number and calculates result
24         calculator.setSecondNumber(-290);
25 
26         // calculate result
27         System.out.println(calculator.getCalculationResult());
28 
29         // user hits CTRL + Z to undo last operation and see last result
30         calculator.restorePreviousCalculation(memento);
31 
32         // result restored
33         System.out.println(calculator.getCalculationResult());
34     }
35 }
View Code
1 输出:
2 110
3 -273
4 110

7. 观察者(Observer)

Intent

定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。

主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

Class Diagram

主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。

观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。

Implementation

天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。

1 public interface Subject {
2     void registerObserver(Observer o);
3 
4     void removeObserver(Observer o);
5 
6     void notifyObserver();
7 }
 1 public class WeatherData implements Subject {
 2     private List<Observer> observers;
 3     private float temperature;
 4     private float humidity;
 5     private float pressure;
 6 
 7     public WeatherData() {
 8         observers = new ArrayList<>();
 9     }
10 
11     public void setMeasurements(float temperature, float humidity, float pressure) {
12         this.temperature = temperature;
13         this.humidity = humidity;
14         this.pressure = pressure;
15         notifyObserver();
16     }
17 
18     @Override
19     public void registerObserver(Observer o) {
20         observers.add(o);
21     }
22 
23     @Override
24     public void removeObserver(Observer o) {
25         int i = observers.indexOf(o);
26         if (i >= 0) {
27             observers.remove(i);
28         }
29     }
30 
31     @Override
32     public void notifyObserver() {
33         for (Observer o : observers) {
34             o.update(temperature, humidity, pressure);
35         }
36     }
37 }
View Code
1 public interface Observer {
2     void update(float temp, float humidity, float pressure);
3 }
 1 public class StatisticsDisplay implements Observer {
 2 
 3     public StatisticsDisplay(Subject weatherData) {
 4         weatherData.registerObserver(this);
 5     }
 6 
 7     @Override
 8     public void update(float temp, float humidity, float pressure) {
 9         System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
10     }
11 }
View Code
 1 public class CurrentConditionsDisplay implements Observer {
 2 
 3     public CurrentConditionsDisplay(Subject weatherData) {
 4         weatherData.registerObserver(this);
 5     }
 6 
 7     @Override
 8     public void update(float temp, float humidity, float pressure) {
 9         System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
10     }
11 }
View Code
 1 public class WeatherStation {
 2     public static void main(String[] args) {
 3         WeatherData weatherData = new WeatherData();
 4         CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
 5         StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
 6 
 7         weatherData.setMeasurements(0, 0, 0);
 8         weatherData.setMeasurements(1, 1, 1);
 9     }
10 }
1 输出:
2 CurrentConditionsDisplay.update: 0.0 0.0 0.0
3 StatisticsDisplay.update: 0.0 0.0 0.0
4 CurrentConditionsDisplay.update: 1.0 1.0 1.0
5 StatisticsDisplay.update: 1.0 1.0 1.0

8. 状态(State)

Intent

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。

Class Diagram

Implementation

糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。

 1 public interface State {
 2     /**
 3      * 投入 25 分钱
 4      */
 5     void insertQuarter();
 6 
 7     /**
 8      * 退回 25 分钱
 9      */
10     void ejectQuarter();
11 
12     /**
13      * 转动曲柄
14      */
15     void turnCrank();
16 
17     /**
18      * 发放糖果
19      */
20     void dispense();
21 }
 1 public class HasQuarterState implements State {
 2 
 3     private GumballMachine gumballMachine;
 4 
 5     public HasQuarterState(GumballMachine gumballMachine) {
 6         this.gumballMachine = gumballMachine;
 7     }
 8 
 9     @Override
10     public void insertQuarter() {
11         System.out.println("You can't insert another quarter");
12     }
13 
14     @Override
15     public void ejectQuarter() {
16         System.out.println("Quarter returned");
17         gumballMachine.setState(gumballMachine.getNoQuarterState());
18     }
19 
20     @Override
21     public void turnCrank() {
22         System.out.println("You turned...");
23         gumballMachine.setState(gumballMachine.getSoldState());
24     }
25 
26     @Override
27     public void dispense() {
28         System.out.println("No gumball dispensed");
29     }
30 }
View Code
 1 public class NoQuarterState implements State {
 2 
 3     GumballMachine gumballMachine;
 4 
 5     public NoQuarterState(GumballMachine gumballMachine) {
 6         this.gumballMachine = gumballMachine;
 7     }
 8 
 9     @Override
10     public void insertQuarter() {
11         System.out.println("You insert a quarter");
12         gumballMachine.setState(gumballMachine.getHasQuarterState());
13     }
14 
15     @Override
16     public void ejectQuarter() {
17         System.out.println("You haven't insert a quarter");
18     }
19 
20     @Override
21     public void turnCrank() {
22         System.out.println("You turned, but there's no quarter");
23     }
24 
25     @Override
26     public void dispense() {
27         System.out.println("You need to pay first");
28     }
29 }
View Code
 1 public class SoldOutState implements State {
 2 
 3     GumballMachine gumballMachine;
 4 
 5     public SoldOutState(GumballMachine gumballMachine) {
 6         this.gumballMachine = gumballMachine;
 7     }
 8 
 9     @Override
10     public void insertQuarter() {
11         System.out.println("You can't insert a quarter, the machine is sold out");
12     }
13 
14     @Override
15     public void ejectQuarter() {
16         System.out.println("You can't eject, you haven't inserted a quarter yet");
17     }
18 
19     @Override
20     public void turnCrank() {
21         System.out.println("You turned, but there are no gumballs");
22     }
23 
24     @Override
25     public void dispense() {
26         System.out.println("No gumball dispensed");
27     }
28 }
View Code
 1 public class SoldState implements State {
 2 
 3     GumballMachine gumballMachine;
 4 
 5     public SoldState(GumballMachine gumballMachine) {
 6         this.gumballMachine = gumballMachine;
 7     }
 8 
 9     @Override
10     public void insertQuarter() {
11         System.out.println("Please wait, we're already giving you a gumball");
12     }
13 
14     @Override
15     public void ejectQuarter() {
16         System.out.println("Sorry, you already turned the crank");
17     }
18 
19     @Override
20     public void turnCrank() {
21         System.out.println("Turning twice doesn't get you another gumball!");
22     }
23 
24     @Override
25     public void dispense() {
26         gumballMachine.releaseBall();
27         if (gumballMachine.getCount() > 0) {
28             gumballMachine.setState(gumballMachine.getNoQuarterState());
29         } else {
30             System.out.println("Oops, out of gumballs");
31             gumballMachine.setState(gumballMachine.getSoldOutState());
32         }
33     }
34 }
View Code
 1 public class GumballMachine {
 2 
 3     private State soldOutState;
 4     private State noQuarterState;
 5     private State hasQuarterState;
 6     private State soldState;
 7 
 8     private State state;
 9     private int count = 0;
10 
11     public GumballMachine(int numberGumballs) {
12         count = numberGumballs;
13         soldOutState = new SoldOutState(this);
14         noQuarterState = new NoQuarterState(this);
15         hasQuarterState = new HasQuarterState(this);
16         soldState = new SoldState(this);
17 
18         if (numberGumballs > 0) {
19             state = noQuarterState;
20         } else {
21             state = soldOutState;
22         }
23     }
24 
25     public void insertQuarter() {
26         state.insertQuarter();
27     }
28 
29     public void ejectQuarter() {
30         state.ejectQuarter();
31     }
32 
33     public void turnCrank() {
34         state.turnCrank();
35         state.dispense();
36     }
37 
38     public void setState(State state) {
39         this.state = state;
40     }
41 
42     public void releaseBall() {
43         System.out.println("A gumball comes rolling out the slot...");
44         if (count != 0) {
45             count -= 1;
46         }
47     }
48 
49     public State getSoldOutState() {
50         return soldOutState;
51     }
52 
53     public State getNoQuarterState() {
54         return noQuarterState;
55     }
56 
57     public State getHasQuarterState() {
58         return hasQuarterState;
59     }
60 
61     public State getSoldState() {
62         return soldState;
63     }
64 
65     public int getCount() {
66         return count;
67     }
68 }
View Code
 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         GumballMachine gumballMachine = new GumballMachine(5);
 5 
 6         gumballMachine.insertQuarter();
 7         gumballMachine.turnCrank();
 8 
 9         gumballMachine.insertQuarter();
10         gumballMachine.ejectQuarter();
11         gumballMachine.turnCrank();
12 
13         gumballMachine.insertQuarter();
14         gumballMachine.turnCrank();
15         gumballMachine.insertQuarter();
16         gumballMachine.turnCrank();
17         gumballMachine.ejectQuarter();
18 
19         gumballMachine.insertQuarter();
20         gumballMachine.insertQuarter();
21         gumballMachine.turnCrank();
22         gumballMachine.insertQuarter();
23         gumballMachine.turnCrank();
24         gumballMachine.insertQuarter();
25         gumballMachine.turnCrank();
26     }
27 }
View Code
 1 输出:
 2 You insert a quarter
 3 You turned...
 4 A gumball comes rolling out the slot...
 5 You insert a quarter
 6 Quarter returned
 7 You turned, but there's no quarter
 8 You need to pay first
 9 You insert a quarter
10 You turned...
11 A gumball comes rolling out the slot...
12 You insert a quarter
13 You turned...
14 A gumball comes rolling out the slot...
15 You haven't insert a quarter
16 You insert a quarter
17 You can't insert another quarter
18 You turned...
19 A gumball comes rolling out the slot...
20 You insert a quarter
21 You turned...
22 A gumball comes rolling out the slot...
23 Oops, out of gumballs
24 You can't insert a quarter, the machine is sold out
25 You turned, but there are no gumballs
26 No gumball dispensed

9. 策略(Strategy)

Intent

定义一系列算法,封装每个算法,并使它们可以互换。

策略模式可以让算法独立于使用它的客户端。

Class Diagram

  • Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
  • Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。

与状态模式的比较

状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。

状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。

Implementation

设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。

1 public interface QuackBehavior {
2     void quack();
3 }
1 public class Quack implements QuackBehavior {
2     @Override
3     public void quack() {
4         System.out.println("quack!");
5     }
6 }
1 public class Squeak implements QuackBehavior{
2     @Override
3     public void quack() {
4         System.out.println("squeak!");
5     }
6 }
 1 public class Duck {
 2 
 3     private QuackBehavior quackBehavior;
 4 
 5     public void performQuack() {
 6         if (quackBehavior != null) {
 7             quackBehavior.quack();
 8         }
 9     }
10 
11     public void setQuackBehavior(QuackBehavior quackBehavior) {
12         this.quackBehavior = quackBehavior;
13     }
14 }
View Code
 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Duck duck = new Duck();
 5         duck.setQuackBehavior(new Squeak());
 6         duck.performQuack();
 7         duck.setQuackBehavior(new Quack());
 8         duck.performQuack();
 9     }
10 }
1 输出:
2 squeak!
3 quack!

10. 模板方法(Template Method)

Intent

定义算法框架,并将一些步骤的实现延迟到子类。

通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

Class Diagram

Implementation

冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。

 1 public abstract class CaffeineBeverage {
 2 
 3     final void prepareRecipe() {
 4         boilWater();
 5         brew();
 6         pourInCup();
 7         addCondiments();
 8     }
 9 
10     abstract void brew();
11 
12     abstract void addCondiments();
13 
14     void boilWater() {
15         System.out.println("boilWater");
16     }
17 
18     void pourInCup() {
19         System.out.println("pourInCup");
20     }
21 }
 1 public class Coffee extends CaffeineBeverage {
 2     @Override
 3     void brew() {
 4         System.out.println("Coffee.brew");
 5     }
 6 
 7     @Override
 8     void addCondiments() {
 9         System.out.println("Coffee.addCondiments");
10     }
11 }
 1 public class Tea extends CaffeineBeverage {
 2     @Override
 3     void brew() {
 4         System.out.println("Tea.brew");
 5     }
 6 
 7     @Override
 8     void addCondiments() {
 9         System.out.println("Tea.addCondiments");
10     }
11 }
1 public class Client {
2     public static void main(String[] args) {
3         CaffeineBeverage caffeineBeverage = new Coffee();
4         caffeineBeverage.prepareRecipe();
5         System.out.println("-----------");
6         caffeineBeverage = new Tea();
7         caffeineBeverage.prepareRecipe();
8     }
9 }
 1 输出:
 2 boilWater
 3 Coffee.brew
 4 pourInCup
 5 Coffee.addCondiments
 6 -----------
 7 boilWater
 8 Tea.brew
 9 pourInCup
10 Tea.addCondiments

11. 访问者(Visitor)

Intent

为一个对象结构(比如组合结构)增加新能力。

Class Diagram

  • Visitor:访问者,为每一个 ConcreteElement 声明一个 visit 操作
  • ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
  • ObjectStructure:对象结构,可以是组合结构,或者是一个集合。

Implementation

1 public interface Element {
2     void accept(Visitor visitor);
3 }
 1 class CustomerGroup {
 2 
 3     private List<Customer> customers = new ArrayList<>();
 4 
 5     void accept(Visitor visitor) {
 6         for (Customer customer : customers) {
 7             customer.accept(visitor);
 8         }
 9     }
10 
11     void addCustomer(Customer customer) {
12         customers.add(customer);
13     }
14 }
View Code
 1 public class Customer implements Element {
 2 
 3     private String name;
 4     private List<Order> orders = new ArrayList<>();
 5 
 6     Customer(String name) {
 7         this.name = name;
 8     }
 9 
10     String getName() {
11         return name;
12     }
13 
14     void addOrder(Order order) {
15         orders.add(order);
16     }
17 
18     public void accept(Visitor visitor) {
19         visitor.visit(this);
20         for (Order order : orders) {
21             order.accept(visitor);
22         }
23     }
24 }
View Code
 1 public class Order implements Element {
 2 
 3     private String name;
 4     private List<Item> items = new ArrayList();
 5 
 6     Order(String name) {
 7         this.name = name;
 8     }
 9 
10     Order(String name, String itemName) {
11         this.name = name;
12         this.addItem(new Item(itemName));
13     }
14 
15     String getName() {
16         return name;
17     }
18 
19     void addItem(Item item) {
20         items.add(item);
21     }
22 
23     public void accept(Visitor visitor) {
24         visitor.visit(this);
25 
26         for (Item item : items) {
27             item.accept(visitor);
28         }
29     }
30 }
View Code
 1 public class Item implements Element {
 2 
 3     private String name;
 4 
 5     Item(String name) {
 6         this.name = name;
 7     }
 8 
 9     String getName() {
10         return name;
11     }
12 
13     public void accept(Visitor visitor) {
14         visitor.visit(this);
15     }
16 }
View Code
1 public interface Visitor {
2     void visit(Customer customer);
3 
4     void visit(Order order);
5 
6     void visit(Item item);
7 }
 1 public class GeneralReport implements Visitor {
 2 
 3     private int customersNo;
 4     private int ordersNo;
 5     private int itemsNo;
 6 
 7     public void visit(Customer customer) {
 8         System.out.println(customer.getName());
 9         customersNo++;
10     }
11 
12     public void visit(Order order) {
13         System.out.println(order.getName());
14         ordersNo++;
15     }
16 
17     public void visit(Item item) {
18         System.out.println(item.getName());
19         itemsNo++;
20     }
21 
22     public void displayResults() {
23         System.out.println("Number of customers: " + customersNo);
24         System.out.println("Number of orders:    " + ordersNo);
25         System.out.println("Number of items:     " + itemsNo);
26     }
27 }
View Code
 1 public class Client {
 2     public static void main(String[] args) {
 3         Customer customer1 = new Customer("customer1");
 4         customer1.addOrder(new Order("order1", "item1"));
 5         customer1.addOrder(new Order("order2", "item1"));
 6         customer1.addOrder(new Order("order3", "item1"));
 7 
 8         Order order = new Order("order_a");
 9         order.addItem(new Item("item_a1"));
10         order.addItem(new Item("item_a2"));
11         order.addItem(new Item("item_a3"));
12         Customer customer2 = new Customer("customer2");
13         customer2.addOrder(order);
14 
15         CustomerGroup customers = new CustomerGroup();
16         customers.addCustomer(customer1);
17         customers.addCustomer(customer2);
18 
19         GeneralReport visitor = new GeneralReport();
20         customers.accept(visitor);
21         visitor.displayResults();
22     }
23 }
View Code
 1 输出:
 2 customer1
 3 order1
 4 item1
 5 order2
 6 item1
 7 order3
 8 item1
 9 customer2
10 order_a
11 item_a1
12 item_a2
13 item_a3
14 Number of customers: 2
15 Number of orders:    4
16 Number of items:     6

12. 空对象(Null)

Intent

使用什么都不做的空对象来代替 NULL。

一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。

Class Diagram

Implementation

1 public abstract class AbstractOperation {
2     abstract void request();
3 }
1 public class RealOperation extends AbstractOperation {
2     @Override
3     void request() {
4         System.out.println("do something");
5     }
6 }
1 public class NullOperation extends AbstractOperation{
2     @Override
3     void request() {
4         // do nothing
5     }
6 }
 1 public class Client {
 2     public static void main(String[] args) {
 3         AbstractOperation abstractOperation = func(-1);
 4         abstractOperation.request();
 5     }
 6 
 7     public static AbstractOperation func(int para) {
 8         if (para < 0) {
 9             return new NullOperation();
10         }
11         return new RealOperation();
12     }
13 }
View Code

 

 

 

日暮乡关何处是?

        烟波江上使人愁

 

 

 

posted @ 2021-07-24 19:45  涛姐涛哥  阅读(323)  评论(0编辑  收藏  举报