行為型
1. 責任鏈(Chain Of Responsibility)
Intent
使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。 將這些對象連成一條鏈,並沿着這條鏈發送該請求,直到有一個對象處理它為止。
Class Diagram
Handler:定義處理請求的接口,並且實現后繼鏈(successor)

Implementation
public abstract classHandler {protectedHandler successor;publicHandler(Handler successor) {this.successor =successor;
}protected abstract voidhandleRequest(Request request);
}public class ConcreteHandler1 extendsHandler {publicConcreteHandler1(Handler successor) {super(successor);
}
@Overrideprotected voidhandleRequest(Request request) {if (request.getType() ==RequestType.TYPE1) {
System.out.println(request.getName()+ " is handle by ConcreteHandler1");return;
}if (successor != null) {
successor.handleRequest(request);
}
}
}public class ConcreteHandler2 extendsHandler {publicConcreteHandler2(Handler successor) {super(successor);
}
@Overrideprotected voidhandleRequest(Request request) {if (request.getType() ==RequestType.TYPE2) {
System.out.println(request.getName()+ " is handle by ConcreteHandler2");return;
}if (successor != null) {
successor.handleRequest(request);
}
}
}public classRequest {privateRequestType type;privateString name;publicRequest(RequestType type, String name) {this.type =type;this.name =name;
}publicRequestType getType() {returntype;
}publicString getName() {returnname;
}
}public enumRequestType {
TYPE1, TYPE2
}public classClient {public static voidmain(String[] args) {
Handler h1=new ConcreteHandler1(null); //h1是沒有后繼的
Handler h2=new ConcreteHandler2(h1);//h2的后繼是h1
Request r1=new Request(RequestType.TYPE1,"request-1");
Request r2=new Request(RequestType.TYPE2,"request-2");//使多個對象都有機會處理請求,從而//TODO:避免請求的發送者和接受者之間的耦合關系。//將這些對象連成一條鏈,並沿着這條鏈發送請求,一直到有一個對象處理它為止。//h2-->h1,這里使用h2處理r1,最終交給h1處理
h2.handleRequest(r1);//h2-->h1,這里h2直接處理
h2.handleRequest(r2);
}
}
request-1is handle by ConcreteHandler1
request-2 is handle by ConcreteHandler2
職責鏈模式會定義一個所有處理請求的對象都要繼承實現的抽象類Handler,這樣就有利於隨時切換新的實現; 其次每個處理請求對象只實現業務流程中的一步業務處理,這樣使其變得簡單; 最后職責鏈模式會動態的來組合這些處理請求的對象, 把它們按照流程動態組合起來,並要求它們依次調用,這樣就動態的實現了流程。
JDK
2. 命令(Command)
Intent
將命令封裝成對象中,具有以下作用:
使用命令來參數化其它對象
將命令放入隊列中進行排隊
將命令的操作記錄到日志中
支持可撤銷的操作
Class Diagram
Command:命令
Receiver:命令接收者,也就是命令真正的執行者
Invoker:通過它來調用命令
Client:可以設置命令與命令的接收者

Implementation1
/*** 接收者,其實是命令的真正執行者*/
public classReceiver {/*** 真正執行命令操作*/
public voidaction(){//真正執行命令操作的功能代碼
System.out.println("真正執行命令操作的功能代碼");
}
}public interfaceCommand {//執行命令的對應操作
public abstract voidexecute();
}public class ConcreteCommand implementsCommand{privateReceiver receiver;publicConcreteCommand(Receiver receiver){this.receiver=receiver;
}
@Overridepublic voidexecute() {
receiver.action();
}
}/*** 命令的調用者*/
public classInvoker {privateCommand command;publicInvoker(Command command){this.command=command;
}//執行命令
public voidexecuteCommand(){
command.execute();
}
}public classClient {public static voidmain(String[] args) {//接收者,其實是命令的真正執行者
Receiver receiver=newReceiver();
Command c=newConcreteCommand(receiver);//命令的調用者
Invoker invoker=newInvoker(c);
invoker.executeCommand();
}
}
Implementation2
設計一個遙控器,可以控制電燈開關。

public interfaceCommand {voidexecute();
}public class LightOnCommand implementsCommand {
Light light;publicLightOnCommand(Light light) {this.light =light;
}
@Overridepublic voidexecute() {
light.on();
}
}public class LightOffCommand implementsCommand {
Light light;publicLightOffCommand(Light light) {this.light =light;
}
@Overridepublic voidexecute() {
light.off();
}
}public classLight {public voidon() {
System.out.println("Light is on!");
}public voidoff() {
System.out.println("Light is off!");
}
}/*** 遙控器,也就是命令的調用者*/
public classRemoteContol {privateCommand[] onCommands;privateCommand[] offCommands;private final int slotNum = 7;publicRemoteContol(){
onCommands=newLightOnCommand[slotNum];
offCommands=newLightOffCommand[slotNum];
}public void setOnCommand(Command command, intslot) {
onCommands[slot]=command;
}public void setOffCommand(Command command, intslot) {
offCommands[slot]=command;
}public void onButtonWasPushed(intslot) {
onCommands[slot].execute();
}public void offButtonWasPushed(intslot) {
offCommands[slot].execute();
}
}public classClient {public static voidmain(String[] args) {
Light light= newLight();
Command lightOnCommand= newLightOnCommand(light);
Command lightOffCommand= newLightOffCommand(light);
RemoteContol remoteContol=newRemoteContol();
remoteContol.setOnCommand(lightOnCommand,0);
remoteContol.setOffCommand(lightOffCommand,0);//執行命令
remoteContol.onButtonWasPushed(0);
remoteContol.offButtonWasPushed(0);
}
}
JDK
3. 解釋器(Interpreter)
Intent
定義一個語法,定義一個解釋器,該解釋器處理該語法句子。
Class Diagram
TerminalExpression:終結符表達式,每個終結符都需要一個 TerminalExpression。
Context:上下文,包含解釋器之外的一些全局信息。

Implementation
以下是一個規則檢驗器實現,具有 and 和 or 規則,通過規則可以構建一顆解析樹,用來檢驗一個文本是否滿足解析樹定義的規則。
例如一顆解析樹為 D And (A Or (B C)),文本 "D A" 滿足該解析樹定義的規則。
這里的 Context 指的是 String。
public abstract classExpression {public abstract booleaninterpret(String str);
}public class TerminalExpression extendsExpression {private String literal = null;publicTerminalExpression(String str) {
literal=str;
}public booleaninterpret(String str) {
StringTokenizer st= newStringTokenizer(str);while(st.hasMoreTokens()) {
String test=st.nextToken();if(test.equals(literal)) {return true;
}
}return false;
}
}public class AndExpression extendsExpression {private Expression expression1 = null;private Expression expression2 = null;publicAndExpression(Expression expression1, Expression expression2) {this.expression1 =expression1;this.expression2 =expression2;
}public booleaninterpret(String str) {return expression1.interpret(str) &&expression2.interpret(str);
}
}public class OrExpression extendsExpression {private Expression expression1 = null;private Expression expression2 = null;publicOrExpression(Expression expression1, Expression expression2) {this.expression1 =expression1;this.expression2 =expression2;
}public booleaninterpret(String str) {return expression1.interpret(str) ||expression2.interpret(str);
}
}public classClient {/*** 構建解析樹*/
public staticExpression buildInterpreterTree() {//Literal
Expression terminal1 = new TerminalExpression("A");
Expression terminal2= new TerminalExpression("B");
Expression terminal3= new TerminalExpression("C");
Expression terminal4= new TerminalExpression("D");//B C
Expression alternation1 = newOrExpression(terminal2, terminal3);//A Or (B C)
Expression alternation2 = newOrExpression(terminal1, alternation1);//D And (A Or (B C))
return newAndExpression(terminal4, alternation2);
}public static voidmain(String[] args) {
Expression define=buildInterpreterTree();
String context1= "D A";
String context2= "A B";
System.out.println(define.interpret(context1));
System.out.println(define.interpret(context2));
}
}
true
false
注意:
1.盡量不要在重要的模塊中使用解釋器模式
2.解釋器在實際系統開發中使用較少
3.可以考慮使用開源的Expression4J、Jep等開源的解析工具包
JDK
4. 迭代器(Iterator)
Intent
提供一種順序訪問聚合對象元素的方法,並且不暴露聚合對象的內部表示。
Class Diagram
Aggregate 是聚合類,其中 createIterator() 方法可以產生一個 Iterator;
Iterator 主要定義了 hasNext() 和 next() 方法。
Client 組合了 Aggregate,為了迭代遍歷 Aggregate,也需要組合 Iterator。

Implementation
public interfaceAggregate {
Iterator createIterator();
}public class ConcreteAggregate implementsAggregate {privateInteger[] items;publicConcreteAggregate() {
items= new Integer[10];for (int i = 0; i < items.length; i++) {
items[i]=i;
}
}
@OverridepublicIterator createIterator() {return new ConcreteIterator(items);
}
}public interface Iterator{
Item next();booleanhasNext();
}public class ConcreteIterator implementsIterator {privateItem[] items;private int position = 0;publicConcreteIterator(Item[] items) {this.items =items;
}
@OverridepublicObject next() {return items[position++];
}
@Overridepublic booleanhasNext() {return position
}
}public classClient {public static voidmain(String[] args) {
Aggregate aggregate= newConcreteAggregate();
Iterator iterator =aggregate.createIterator();while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
JDK
5. 中介者(Mediator)
Intent
集中相關對象之間復雜的溝通和控制方式。
Class Diagram
Mediator:中介者,定義一個接口用於與各同事(Colleague)對象通信。
Colleague:同事,相關對象

Implementation
Alarm(鬧鍾)、CoffeePot(咖啡壺)、Calendar(日歷)、Sprinkler(噴頭)是一組相關的對象,在某個對象的事件產生時需要去操作其它對象,形成了下面這種依賴結構:

使用中介者模式可以將復雜的依賴結構變成星形結構:

public abstract classColleague {public abstract voidonEvent(Mediator mediator);
}public class Alarm extendsColleague {
@Overridepublic voidonEvent(Mediator mediator) {
mediator.doEvent("alarm");
}public voiddoAlarm() {
System.out.println("doAlarm()");
}
}public class CoffeePot extendsColleague {
@Overridepublic voidonEvent(Mediator mediator) {
mediator.doEvent("coffeePot");
}public voiddoCoffeePot() {
System.out.println("doCoffeePot()");
}
}public class Calendar extendsColleague{
@Overridepublic voidonEvent(Mediator mediator) {
mediator.doEvent("calendar");
}public voiddoCalendar(){
System.out.println("doCalendar()");
}
}public class Sprinkler extendsColleague {
@Overridepublic voidonEvent(Mediator mediator) {
mediator.doEvent("sprinkler");
}public voiddoSprinkler() {
System.out.println("doSprinkler()");
}
}public abstract classMediator {public abstract voiddoEvent(String eventType);
}public class ConcreteMediator extendsMediator{privateAlarm alarm;privateCoffeePot coffeePot;privateCalendar calendar;privateSprinkler sprinkler;publicConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calendar calendar, Sprinkler sprinkler) {this.alarm =alarm;this.coffeePot =coffeePot;this.calendar =calendar;this.sprinkler =sprinkler;
}
@Overridepublic voiddoEvent(String eventType) {switch(eventType) {case "alarm":
doAlarmEvent();break;case "coffeePot":
doCoffeePotEvent();break;case "calendar":
doCalenderEvent();break;default:
doSprinklerEvent();
}
}public voiddoAlarmEvent() {
alarm.doAlarm();
coffeePot.doCoffeePot();
calendar.doCalendar();
sprinkler.doSprinkler();
}public voiddoCoffeePotEvent() {//...
}public voiddoCalenderEvent() {//...
}public voiddoSprinklerEvent() {//...
}
}public classClient {public static voidmain(String[] args) {
Alarm alarm= newAlarm();
CoffeePot coffeePot= newCoffeePot();
Calendar calender= newCalendar();
Sprinkler sprinkler= newSprinkler();
Mediator mediator= newConcreteMediator(alarm, coffeePot, calender, sprinkler);//鬧鍾事件到達,調用中介者就可以操作相關對象
alarm.onEvent(mediator);
}
}
doAlarm()
doCoffeePot()
doCalendar()
doSprinkler()
JDK
6. 備忘錄(Memento)
Intent
在不違反封裝的情況下獲得對象的內部狀態,從而在需要時可以將對象恢復到最初狀態。
Class Diagram
Originator:原始對象
Caretaker:負責保存好備忘錄
Menento:備忘錄,存儲原始對象的的狀態。 備忘錄實際上有兩個接口,一個是提供給 Caretaker 的窄接口:它只能將備忘錄傳遞給其它對象; 一個是提供給 Originator 的寬接口,允許它訪問到先前狀態所需的所有數據。理想情況是只允許 Originator 訪問本備忘錄的內部狀態。

Implementation
以下實現了一個簡單計算器程序,可以輸入兩個值,然后計算這兩個值的和。 備忘錄模式允許將這兩個值存儲起來,然后在某個時刻用存儲的狀態進行恢復。
/*** Originator Interface*/
public interfaceCalculator {//Create Memento
PreviousCalculationToCareTaker backupLastCalculation();//setMemento
voidrestorePreviousCalculation(PreviousCalculationToCareTaker memento);intgetCalculationResult();void setFirstNumber(intfirstNumber);void setSecondNumber(intsecondNumber);
}/*** Originator Implementation*/
public class CalculatorImp implementsCalculator {private intfirstNumber;private intsecondNumber;
@OverridepublicPreviousCalculationToCareTaker backupLastCalculation() {//create a memento object used for restoring two numbers
return newPreviousCalculationImp(firstNumber, secondNumber);
}
@Overridepublic voidrestorePreviousCalculation(PreviousCalculationToCareTaker memento) {this.firstNumber =((PreviousCalculationToOriginator) memento).getFirstNumber();this.secondNumber =((PreviousCalculationToOriginator) memento).getSecondNumber();
}
@Overridepublic intgetCalculationResult() {//result is adding two numbers
return firstNumber +secondNumber;
}
@Overridepublic void setFirstNumber(intfirstNumber) {this.firstNumber =firstNumber;
}
@Overridepublic void setSecondNumber(intsecondNumber) {this.secondNumber =secondNumber;
}
}/*** Memento Interface to Originator
*
* This interface allows the originator to restore its state*/
public interfacePreviousCalculationToOriginator {intgetFirstNumber();intgetSecondNumber();
}/*** Memento interface to CalculatorOperator (Caretaker)*/
public interfacePreviousCalculationToCareTaker {//no operations permitted for the caretaker
}/*** Memento Object Implementation
*
* Note that this object implements both interfaces to Originator and CareTaker*/
public class PreviousCalculationImp implementsPreviousCalculationToCareTaker,
PreviousCalculationToOriginator {private intfirstNumber;private intsecondNumber;public PreviousCalculationImp(int firstNumber, intsecondNumber) {this.firstNumber =firstNumber;this.secondNumber =secondNumber;
}
@Overridepublic intgetFirstNumber() {returnfirstNumber;
}
@Overridepublic intgetSecondNumber() {returnsecondNumber;
}
}/*** CareTaker object*/
public classClient {public static voidmain(String[] args) {//program starts
Calculator calculator = newCalculatorImp();//assume user enters two numbers
calculator.setFirstNumber(10);
calculator.setSecondNumber(100);//find result
System.out.println(calculator.getCalculationResult());//Store result of this calculation in case of error
PreviousCalculationToCareTaker memento =calculator.backupLastCalculation();//user enters a number
calculator.setFirstNumber(17);//user enters a wrong second number and calculates result
calculator.setSecondNumber(-290);//calculate result
System.out.println(calculator.getCalculationResult());//user hits CTRL + Z to undo last operation and see last result
calculator.restorePreviousCalculation(memento);//result restored
System.out.println(calculator.getCalculationResult());
}
}
110
-273
110
JDK
java.io.Serializable
7. 觀察者(Observer)
Intent
定義對象之間的一對多依賴,當一個對象狀態改變時,它的所有依賴都會收到通知並且自動更新狀態。
主題(Subject)是被觀察的對象,而其所有依賴者(Observer)稱為觀察者。

Class Diagram
主題(Subject)具有注冊和移除觀察者、並通知所有觀察者的功能,主題是通過維護一張觀察者列表來實現這些操作的。
觀察者(Observer)的注冊功能需要調用主題的 registerObserver() 方法。

Implementation
天氣數據布告板會在天氣信息發生改變時更新其內容,布告板有多個,並且在將來會繼續增加。

public interfaceSubject {voidregisterObserver(Observer o);voidremoveObserver(Observer o);voidnotifyObserver();
}public class WeatherData implementsSubject {private Listobservers;private floattemperature;private floathumidity;private floatpressure;publicWeatherData() {
observers= new ArrayList<>();
}public void setMeasurements(float temperature, float humidity, floatpressure) {this.temperature =temperature;this.humidity =humidity;this.pressure =pressure;
notifyObserver();
}
@Overridepublic voidregisterObserver(Observer o) {
observers.add(o);
}
@Overridepublic voidremoveObserver(Observer o) {int i =observers.indexOf(o);if (i >= 0) {
observers.remove(i);
}
}
@Overridepublic voidnotifyObserver() {for(Observer o : observers) {
o.update(temperature, humidity, pressure);
}
}
}public interfaceObserver {void update(float temp, float humidity, floatpressure);
}public class StatisticsDisplay implementsObserver {publicStatisticsDisplay(Subject weatherData) {
weatherData.reisterObserver(this);
}
@Overridepublic void update(float temp, float humidity, floatpressure) {
System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " +pressure);
}
}public class CurrentConditionsDisplay implementsObserver {publicCurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Overridepublic void update(float temp, float humidity, floatpressure) {
System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " +pressure);
}
}/*** 天氣預報*/
public classWeatherForecast {public static voidmain(String[] args) {
WeatherData weatherData=newWeatherData();
Observer observer=newStatisticsDisplay(weatherData);
Observer observer2=newCurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(0.0f,0.0f,0.0f);
weatherData.setMeasurements(1.0f,1.0f,1.0f);
}
}
CurrentConditionsDisplay.update: 0.0 0.0 0.0StatisticsDisplay.update:0.0 0.0 0.0CurrentConditionsDisplay.update:1.0 1.0 1.0StatisticsDisplay.update:1.0 1.0 1.0
JDK
8. 狀態(State)
Intent
允許對象在內部狀態改變時改變它的行為,對象看起來好像修改了它所屬的類。
Class Diagram
Context:環境,也稱上下文,通常用來定義客戶感興趣的接口,同時維護一個來具體處理當前狀態的實例對象。
State:狀態接口,用來封裝與上下文的一個特定狀態所對應的行為。
ConcreteState:具體實現狀態處理的類,每個類實現一個跟上下文相關的狀態的具體處理。

Implementation1
實現在線投票:
一個在線投票的應用,要實現控制同一個用戶只能投一票,如果一個用戶反復投票,而且投票次數超過5次, 則判定為惡意刷票,要取消該用戶投票的資格,當然同時也要取消他所投的票。 如果一個用戶的投票次數超過8次,將進入黑名單,禁止再登錄和使用系統。
在投票的過程中,又有四種情況:
用戶是正常投票
用戶正常投票過后,有意或者無意的重復投票
用戶惡意投票
黑名單用戶
程序結構如下圖:

/*** 封裝一個投票狀態相關的行為*/
public interfaceVoteState {/*** TODO:處理狀態對應的行為
*@paramvoter 投票人
*@paramvoteManager 投票上下文,用來在實現狀態對應的功能處理的時候,可以回調上下文的數據*/
voidvote(String voter, VoteManager voteManager);
}/*** 投票管理器*/
public classVoteManager {//持有狀態處理對象
private VoteState state = null;//統計用戶投票數
private Map mapVoteCount = new HashMap();public MapgetMapVoteCount(){returnmapVoteCount;
}/*** 投票
*@paramuser 投票人,為了簡單,就是用戶名稱*/
public voidvote(String user){//1:先為該用戶增加投票的次數
int voteCount=mapVoteCount.getOrDefault(user,0);
mapVoteCount.put(user,++voteCount);//2:判斷該用戶投票的類型,就相當於是判斷對應的狀態//到底是正常投票、重復投票、惡意投票還是上黑名單的狀態
if(voteCount==1){
state= newNormalVoteState();
}else if(voteCount>1 && voteCount<5){
state= newRepeatVoteState();
}else if(voteCount >= 5 && voteCount<8){
state= newSpiteVoteState();
}else if(voteCount>=8){
state= newBlackVoteState();
}//然后轉調狀態對象來進行相應的操作
state.vote(user, this);
}
}/*** 正常投票*/
public class NormalVoteState implementsVoteState{
@Overridepublic voidvote(String voter, VoteManager voteManager) {
System.out.println("恭喜你投票成功");
}
}/*** 重復投票*/
public class RepeatVoteState implementsVoteState{
@Overridepublic voidvote(String voter, VoteManager voteManager) {
System.out.println("請不要重復投票");
}
}/*** 惡意投票*/
public class SpiteVoteState implementsVoteState{
@Overridepublic voidvote(String voter, VoteManager voteManager) {
System.out.println("你有惡意刷票行為,取消投票資格");
}
}/*** 黑名單
* 記入黑名單中,禁止登錄系統了*/
public class BlackVoteState implementsVoteState{
@Overridepublic voidvote(String voter, VoteManager voteManager) {
System.out.println("進入黑名單,將禁止登錄和使用本系統");
}
}public classClient {public static voidmain(String[] args) {
VoteManager vm= newVoteManager();for (int i = 0; i < 9; i++) {
vm.vote("u1");
}
}
}
輸出結果:
恭喜你投票成功
請不要重復投票
請不要重復投票
請不要重復投票
你有惡意刷票行為,取消投票資格
你有惡意刷票行為,取消投票資格
你有惡意刷票行為,取消投票資格
進入黑名單,將禁止登錄和使用本系統
進入黑名單,將禁止登錄和使用本系統
Implementation2
糖果銷售機有多種狀態,每種狀態下銷售機有不同的行為,狀態可以發生轉移,使得銷售機的行為也發生改變。

public interfaceState {/*** 投入 25 分錢*/
voidinsertQuarter();/*** 退回 25 分錢*/
voidejectQuarter();/*** 轉動曲柄*/
voidturnCrank();/*** 發放糖果*/
voiddispense();
}public class HasQuarterState implementsState {privateGumballMachine gumballMachine;publicHasQuarterState(GumballMachine gumballMachine) {this.gumballMachine =gumballMachine;
}
@Overridepublic voidinsertQuarter() {
System.out.println("You can't insert another quarter");
}
@Overridepublic voidejectQuarter() {
System.out.println("Quarter returned");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Overridepublic voidturnCrank() {
System.out.println("You turned...");
gumballMachine.setState(gumballMachine.getSoldState());
}
@Overridepublic voiddispense() {
System.out.println("No gumball dispensed");
}
}public class NoQuarterState implementsState {
GumballMachine gumballMachine;publicNoQuarterState(GumballMachine gumballMachine) {this.gumballMachine =gumballMachine;
}
@Overridepublic voidinsertQuarter() {
System.out.println("You insert a quarter");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Overridepublic voidejectQuarter() {
System.out.println("You haven't insert a quarter");
}
@Overridepublic voidturnCrank() {
System.out.println("You turned, but there's no quarter");
}
@Overridepublic voiddispense() {
System.out.println("You need to pay first");
}
}public class SoldOutState implementsState {
GumballMachine gumballMachine;publicSoldOutState(GumballMachine gumballMachine) {this.gumballMachine =gumballMachine;
}
@Overridepublic voidinsertQuarter() {
System.out.println("You can't insert a quarter, the machine is sold out");
}
@Overridepublic voidejectQuarter() {
System.out.println("You can't eject, you haven't inserted a quarter yet");
}
@Overridepublic voidturnCrank() {
System.out.println("You turned, but there are no gumballs");
}
@Overridepublic voiddispense() {
System.out.println("No gumball dispensed");
}
}public class SoldState implementsState {
GumballMachine gumballMachine;publicSoldState(GumballMachine gumballMachine) {this.gumballMachine =gumballMachine;
}
@Overridepublic voidinsertQuarter() {
System.out.println("Please wait, we're already giving you a gumball");
}
@Overridepublic voidejectQuarter() {
System.out.println("Sorry, you already turned the crank");
}
@Overridepublic voidturnCrank() {
System.out.println("Turning twice doesn't get you another gumball!");
}
@Overridepublic voiddispense() {
gumballMachine.releaseBall();if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
}else{
System.out.println("Oops, out of gumballs");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}public classGumballMachine {privateState soldOutState;privateState noQuarterState;privateState hasQuarterState;privateState soldState;privateState state;private int count = 0;public GumballMachine(intnumberGumballs) {
count=numberGumballs;
soldOutState= new SoldOutState(this);
noQuarterState= new NoQuarterState(this);
hasQuarterState= new HasQuarterState(this);
soldState= new SoldState(this);if (numberGumballs > 0) {
state=noQuarterState;
}else{
state=soldOutState;
}
}public voidinsertQuarter() {
state.insertQuarter();
}public voidejectQuarter() {
state.ejectQuarter();
}public voidturnCrank() {
state.turnCrank();
state.dispense();
}public voidsetState(State state) {this.state =state;
}public voidreleaseBall() {
System.out.println("A gumball comes rolling out the slot...");if (count != 0) {
count-= 1;
}
}publicState getSoldOutState() {returnsoldOutState;
}publicState getNoQuarterState() {returnnoQuarterState;
}publicState getHasQuarterState() {returnhasQuarterState;
}publicState getSoldState() {returnsoldState;
}public intgetCount() {returncount;
}
}public classClient {public static voidmain(String[] args) {
GumballMachine gumballMachine= new GumballMachine(5);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.ejectQuarter();
gumballMachine.insertQuarter();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
}
}
You insert a quarter
You turned...
A gumball comes rolling out the slot...
You insert a quarter
Quarter returned
You turned, but there's no quarter
You need to pay first
You insert a quarter
You turned...
A gumball comes rolling out the slot...
You insert a quarter
You turned...
A gumball comes rolling out the slot...
You haven't insert a quarter
You insert a quarter
You can't insert another quarter
You turned...
A gumball comes rolling out the slot...
You insert a quarter
You turned...
A gumball comes rolling out the slot...
Oops, out of gumballs
You can't insert a quarter, the machine is sold out
You turned, but there are no gumballs
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 使用的算法。
Implementation1
設計一個鴨子,它可以動態地改變叫聲。這里的算法族是鴨子的叫聲行為。
public interfaceQuackBehavior {voidquack();
}public class Quack implementsQuackBehavior {
@Overridepublic voidquack() {
System.out.println("quack!");
}
}public class Squeak implementsQuackBehavior{
@Overridepublic voidquack() {
System.out.println("squeak!");
}
}public classDuck {privateQuackBehavior quackBehavior;public voidperformQuack() {if (quackBehavior != null) {
quackBehavior.quack();
}
}public voidsetQuackBehavior(QuackBehavior quackBehavior) {this.quackBehavior =quackBehavior;
}
}public classClient {public static voidmain(String[] args) {
Duck duck= newDuck();
duck.setQuackBehavior(newSqueak());
duck.performQuack();
duck.setQuackBehavior(newQuack());
duck.performQuack();
}
}
squeak!quack!
Implementation2
報價管理:向客戶報價,對於銷售部門的人來講,這是一個非常重大、非常復雜的問題,對不同的客戶要報不同的價格,比如:
對普通客戶或者是新客戶報的是全價
對老客戶報的價格,根據客戶年限,給予一定的折扣
對大客戶報的價格,根據大客戶的累計消費金額,給予一定的折扣

/*** 策略,定義計算報價算法的接口*/
public interfaceStrategy {/*** 計算報價
*@paramgoodsPrice 商品原價
*@return
*/
double calcPrice(doublegoodsPrice);
}public class NormalCustomerStrategy implementsStrategy{
@Overridepublic double calcPrice(doublegoodsPrice) {
System.out.println("對於新客戶或者是普通客戶,沒有折扣");returngoodsPrice;
}
}public class OldCustomerStrategy implementsStrategy{
@Overridepublic double calcPrice(doublegoodsPrice) {
System.out.println("對於老客戶,統一折扣5%");return goodsPrice*(1-0.05);
}
}public class LargeCustomerStrategy implementsStrategy{
@Overridepublic double calcPrice(doublegoodsPrice) {
System.out.println("對於大客戶,統一折扣10%");return goodsPrice*(1-0.1);
}
}public classPrice {privateStrategy strategy;public double price(doublegoodsPrice){returnstrategy.calcPrice(goodsPrice);
}public voidsetStrategy(Strategy strategy) {this.strategy =strategy;
}
}public classClient {public static voidmain(String[] args) {//1:選擇並創建需要使用的策略對象
Strategy strategy = newBigCustomerStrategy ();//2:創建上下文
Price ctx = newPrice();
ctx.setStrategy(strategy);//3:計算報價
double price = ctx.price(1000);
System.out.println("向客戶報價:"+price);
}
}
JDK
java.util.Comparator#compare()
javax.servlet.http.HttpServlet
javax.servlet.Filter#doFilter()
10. 模板方法(Template Method)
Intent
定義算法框架,並將一些步驟的實現延遲到子類。
通過模板方法,子類可以重新定義算法的某些步驟,而不用改變算法的結構。
Class Diagram

Implementation
沖咖啡和沖茶都有類似的流程,但是某些步驟會有點不一樣,要求復用那些相同步驟的代碼。

public abstract classCaffeineBeverage {final voidprepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}abstract voidbrew();abstract voidaddCondiments();voidboilWater() {
System.out.println("boilWater");
}voidpourInCup() {
System.out.println("pourInCup");
}
}public class Coffee extendsCaffeineBeverage {
@Overridevoidbrew() {
System.out.println("Coffee.brew");
}
@OverridevoidaddCondiments() {
System.out.println("Coffee.addCondiments");
}
}public class Tea extendsCaffeineBeverage {
@Overridevoidbrew() {
System.out.println("Tea.brew");
}
@OverridevoidaddCondiments() {
System.out.println("Tea.addCondiments");
}
}public classClient {public static voidmain(String[] args) {
CaffeineBeverage caffeineBeverage= newCoffee();
caffeineBeverage.prepareRecipe();
System.out.println("-----------");
caffeineBeverage= newTea();
caffeineBeverage.prepareRecipe();
}
}
boilWater
Coffee.brew
pourInCup
Coffee.addCondiments-----------boilWater
Tea.brew
pourInCup
Tea.addCondiments
JDK
java.util.Collections#sort()
java.io.InputStream#skip()
java.io.InputStream#read()
java.util.AbstractList#indexOf()
11. 訪問者(Visitor)
Intent
為一個對象結構(比如組合結構)增加新能力。
Class Diagram
Visitor:訪問者,為每一個 ConcreteElement 聲明一個 visit 操作
ConcreteVisitor:具體訪問者,存儲遍歷過程中的累計結果
ObjectStructure:對象結構,可以是組合結構,或者是一個集合。

Implementation
public interfaceElement {voidaccept(Visitor visitor);
}classCustomerGroup {private List customers = new ArrayList<>();voidaccept(Visitor visitor) {for(Customer customer : customers) {
customer.accept(visitor);
}
}voidaddCustomer(Customer customer) {
customers.add(customer);
}
}public class Customer implementsElement {privateString name;private List orders = new ArrayList<>();
Customer(String name) {this.name =name;
}
String getName() {returnname;
}voidaddOrder(Order order) {
orders.add(order);
}public voidaccept(Visitor visitor) {
visitor.visit(this);for(Order order : orders) {
order.accept(visitor);
}
}
}public class Order implementsElement {privateString name;private List items = newArrayList();
Order(String name) {this.name =name;
}
Order(String name, String itemName) {this.name =name;this.addItem(newItem(itemName));
}
String getName() {returnname;
}voidaddItem(Item item) {
items.add(item);
}public voidaccept(Visitor visitor) {
visitor.visit(this);for(Item item : items) {
item.accept(visitor);
}
}
}public class Item implementsElement {privateString name;
Item(String name) {this.name =name;
}
String getName() {returnname;
}public voidaccept(Visitor visitor) {
visitor.visit(this);
}
}public interfaceVisitor {voidvisit(Customer customer);voidvisit(Order order);voidvisit(Item item);
}public class GeneralReport implementsVisitor {private intcustomersNo;private intordersNo;private intitemsNo;public voidvisit(Customer customer) {
System.out.println(customer.getName());
customersNo++;
}public voidvisit(Order order) {
System.out.println(order.getName());
ordersNo++;
}public voidvisit(Item item) {
System.out.println(item.getName());
itemsNo++;
}public voiddisplayResults() {
System.out.println("Number of customers: " +customersNo);
System.out.println("Number of orders: " +ordersNo);
System.out.println("Number of items: " +itemsNo);
}
}
public classClient {public static voidmain(String[] args) {
Customer customer1= new Customer("customer1");
customer1.addOrder(new Order("order1", "item1"));
customer1.addOrder(new Order("order2", "item1"));
customer1.addOrder(new Order("order3", "item1"));
Order order= new Order("order_a");
order.addItem(new Item("item_a1"));
order.addItem(new Item("item_a2"));
order.addItem(new Item("item_a3"));
Customer customer2= new Customer("customer2");
customer2.addOrder(order);
CustomerGroup customers= newCustomerGroup();
customers.addCustomer(customer1);
customers.addCustomer(customer2);
GeneralReport visitor= newGeneralReport();
customers.accept(visitor);
visitor.displayResults();
}
}
customer1
order1
item1
order2
item1
order3
item1
customer2
order_a
item_a1
item_a2
item_a3
Number of customers:2Number of orders:4Number of items:6
JDK
javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor
12. 空對象(Null)
Intent
使用什么都不做的空對象來代替 NULL。
一個方法返回 NULL,意味着方法的調用端需要去檢查返回值是否是 NULL,這么做會導致非常多的冗余的檢查代碼。並且如果某一個調用端忘記了做這個檢查返回值,而直接使用返回的對象,那么就有可能拋出空指針異常。
Class Diagram

Implementation
public abstract classAbstractOperation {abstract voidrequest();
}public class RealOperation extendsAbstractOperation {
@Overridevoidrequest() {
System.out.println("do something");
}
}public class NullOperation extendsAbstractOperation{
@Overridevoidrequest() {//do nothing
}
}public classClient {public static voidmain(String[] args) {
AbstractOperation abstractOperation= func(-1);
abstractOperation.request();
}public static AbstractOperation func(intpara) {if (para < 0) {return newNullOperation();
}return newRealOperation();
}
}
免費Java高級資料需要自己領取,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高並發分布式等教程,一共30G。
本文详细介绍了行为型设计模式中的责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。通过具体的实例,展示了每种模式的应用场景和实现方式。
705

被折叠的 条评论
为什么被折叠?



