面向對象-設計模式-行爲型

面向對象-設計模式-行爲型算法

 

      日暮鄉關何處是?煙波江上令人愁。express

 

簡介:面向對象-設計模式-行爲型。設計模式

1、概述

何謂設計模式框架

設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、通過分類的、代碼設計經驗的總結。ide

設計模式的好處&學習目的學習

一、爲了代碼可重用行、讓代碼更易被他人理解、保證代碼的可靠性、使代碼編寫真正實現工程化;ui

二、設計模式便於咱們維護項目,加強系統的健壯性和可擴展性;this

三、設計模式還能夠鍛鍊碼農的設計思惟、昇華代碼質量等。spa

2、行爲型

責任鏈模式、命令模式、解釋器模式、迭代器模式、中介者模式、備忘錄模式、觀察者模式、狀態模式、策略模式、模板方法模式、訪問者模式、空對象模式。設計

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

 

 

 

日暮鄉關何處是?

        煙波江上令人愁

相關文章
相關標籤/搜索