java spite截取_Java內功心法,行為型設計模式

本文详细介绍了行为型设计模式中的责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。通过具体的实例,展示了每种模式的应用场景和实现方式。

行為型

1. 責任鏈(Chain Of Responsibility)

Intent

使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。 將這些對象連成一條鏈,並沿着這條鏈發送該請求,直到有一個對象處理它為止。

Class Diagram

Handler:定義處理請求的接口,並且實現后繼鏈(successor)

a0ec833272dffd7fc0170704db3d50ab1.jpg

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:可以設置命令與命令的接收者

a0ec833272dffd7fc0170704db3d50ab2.jpg

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

設計一個遙控器,可以控制電燈開關。

a0ec833272dffd7fc0170704db3d50ab3.jpg

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:上下文,包含解釋器之外的一些全局信息。

a0ec833272dffd7fc0170704db3d50ab4.jpg

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。

a0ec833272dffd7fc0170704db3d50ab5.jpg

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:同事,相關對象

a0ec833272dffd7fc0170704db3d50ab6.jpg

Implementation

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

a0ec833272dffd7fc0170704db3d50ab7.jpg

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

a0ec833272dffd7fc0170704db3d50ab8.jpg

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 訪問本備忘錄的內部狀態。

a0ec833272dffd7fc0170704db3d50ab9.jpg

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)稱為觀察者。

a0ec833272dffd7fc0170704db3d50ab10.jpg

Class Diagram

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

觀察者(Observer)的注冊功能需要調用主題的 registerObserver() 方法。

a0ec833272dffd7fc0170704db3d50ab11.jpg

Implementation

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

a0ec833272dffd7fc0170704db3d50ab12.jpg

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:具體實現狀態處理的類,每個類實現一個跟上下文相關的狀態的具體處理。

a0ec833272dffd7fc0170704db3d50ab13.jpg

Implementation1

實現在線投票:

一個在線投票的應用,要實現控制同一個用戶只能投一票,如果一個用戶反復投票,而且投票次數超過5次, 則判定為惡意刷票,要取消該用戶投票的資格,當然同時也要取消他所投的票。 如果一個用戶的投票次數超過8次,將進入黑名單,禁止再登錄和使用系統。

在投票的過程中,又有四種情況:

用戶是正常投票

用戶正常投票過后,有意或者無意的重復投票

用戶惡意投票

黑名單用戶

程序結構如下圖:

a0ec833272dffd7fc0170704db3d50ab14.jpg

/*** 封裝一個投票狀態相關的行為*/

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

糖果銷售機有多種狀態,每種狀態下銷售機有不同的行為,狀態可以發生轉移,使得銷售機的行為也發生改變。

a0ec833272dffd7fc0170704db3d50ab15.jpg

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 所使用的算法。

a0ec833272dffd7fc0170704db3d50ab16.jpg

與狀態模式的比較

狀態模式的類圖和策略模式類似,並且都是能夠動態改變對象的行為。 但是狀態模式是通過狀態轉移來改變 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

報價管理:向客戶報價,對於銷售部門的人來講,這是一個非常重大、非常復雜的問題,對不同的客戶要報不同的價格,比如:

對普通客戶或者是新客戶報的是全價

對老客戶報的價格,根據客戶年限,給予一定的折扣

對大客戶報的價格,根據大客戶的累計消費金額,給予一定的折扣

a0ec833272dffd7fc0170704db3d50ab17.jpg

/*** 策略,定義計算報價算法的接口*/

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

a0ec833272dffd7fc0170704db3d50ab18.jpg

Implementation

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

a0ec833272dffd7fc0170704db3d50ab19.jpg

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:對象結構,可以是組合結構,或者是一個集合。

a0ec833272dffd7fc0170704db3d50ab20.jpg

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

a0ec833272dffd7fc0170704db3d50ab21.jpg

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。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值