溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)

發(fā)布時(shí)間:2020-07-26 22:38:53 來源:網(wǎng)絡(luò) 閱讀:184 作者:Java筆記丶 欄目:編程語(yǔ)言
本人免費(fèi)整理了Java高級(jí)資料,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并發(fā)分布式等教程,一共30G,需要自己領(lǐng)取。
傳送門:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q

1.責(zé)任鏈(Chain Of Responsibility)

Intent

使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系。將這些對(duì)象連成一條鏈,并沿著這條鏈發(fā)送該請(qǐng)求,直到有一個(gè)對(duì)象處理它為止。

Class Diagram

  • Handler:定義處理請(qǐng)求的接口,并且實(shí)現(xiàn)后繼鏈(successor)


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

public?abstract?class?Handler?{

????protected?Handler?successor;


????public?Handler(Handler?successor)?{
????????this.successor?=?successor;
????}


????protected?abstract?void?handleRequest(Request?request);}public?class?ConcreteHandler1?extends?Handler?{

????public?ConcreteHandler1(Handler?successor)?{
????????super(successor);
????}


????@Override
????protected?void?handleRequest(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?extends?Handler?{

????public?ConcreteHandler2(Handler?successor)?{
????????super(successor);
????}


????@Override
????protected?void?handleRequest(Request?request)?{
????????if?(request.getType()?==?RequestType.TYPE2)?{
????????????System.out.println(request.getName()?+?"?is?handle?by?ConcreteHandler2");
????????????return;
????????}
????????if?(successor?!=?null)?{
????????????successor.handleRequest(request);
????????}
????}}public?class?Request?{

????private?RequestType?type;
????private?String?name;


????public?Request(RequestType?type,?String?name)?{
????????this.type?=?type;
????????this.name?=?name;
????}


????public?RequestType?getType()?{
????????return?type;
????}


????public?String?getName()?{
????????return?name;
????}}public?enum?RequestType?{
????TYPE1,?TYPE2}public?class?Client?{

????public?static?void?main(String[]?args)?{

????????Handler?handler1?=?new?ConcreteHandler1(null);
????????Handler?handler2?=?new?ConcreteHandler2(handler1);

????????Request?request1?=?new?Request(RequestType.TYPE1,?"request1");
????????handler2.handleRequest(request1);

????????Request?request2?=?new?Request(RequestType.TYPE2,?"request2");
????????handler2.handleRequest(request2);
????}}request1?is?handle?by?ConcreteHandler1request2?is?handle?by?ConcreteHandler2

JDK

  • java.util.logging.Logger#log()

  • Apache Commons Chain

  • javax.servlet.Filter#doFilter()

2. 命令(Command)

Intent

將命令封裝成對(duì)象中,具有以下作用:

  • 使用命令來參數(shù)化其它對(duì)象

  • 將命令放入隊(duì)列中進(jìn)行排隊(duì)

  • 將命令的操作記錄到日志中

  • 支持可撤銷的操作

Class Diagram

  • Command:命令

  • Receiver:命令接收者,也就是命令真正的執(zhí)行者

  • Invoker:通過它來調(diào)用命令

  • Client:可以設(shè)置命令與命令的接收者


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

設(shè)計(jì)一個(gè)遙控器,可以控制電燈開關(guān)。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



public?interface?Command?{
????void?execute();}public?class?LightOnCommand?implements?Command?{
????Light?light;

????public?LightOnCommand(Light?light)?{
????????this.light?=?light;
????}

????@Override
????public?void?execute()?{
????????light.on();
????}}public?class?LightOffCommand?implements?Command?{
????Light?light;

????public?LightOffCommand(Light?light)?{
????????this.light?=?light;
????}

????@Override
????public?void?execute()?{
????????light.off();
????}}public?class?Light?{

????public?void?on()?{
????????System.out.println("Light?is?on!");
????}

????public?void?off()?{
????????System.out.println("Light?is?off!");
????}}/**?*?遙控器?*/public?class?Invoker?{
????private?Command[]?onCommands;
????private?Command[]?offCommands;
????private?final?int?slotNum?=?7;

????public?Invoker()?{
????????this.onCommands?=?new?Command[slotNum];
????????this.offCommands?=?new?Command[slotNum];
????}

????public?void?setOnCommand(Command?command,?int?slot)?{
????????onCommands[slot]?=?command;
????}

????public?void?setOffCommand(Command?command,?int?slot)?{
????????offCommands[slot]?=?command;
????}

????public?void?onButtonWasPushed(int?slot)?{
????????onCommands[slot].execute();
????}

????public?void?offButtonWasPushed(int?slot)?{
????????offCommands[slot].execute();
????}}public?class?Client?{
????public?static?void?main(String[]?args)?{
????????Invoker?invoker?=?new?Invoker();
????????Light?light?=?new?Light();
????????Command?lightOnCommand?=?new?LightOnCommand(light);
????????Command?lightOffCommand?=?new?LightOffCommand(light);
????????invoker.setOnCommand(lightOnCommand,?0);
????????invoker.setOffCommand(lightOffCommand,?0);
????????invoker.onButtonWasPushed(0);
????????invoker.offButtonWasPushed(0);
????}}

JDK

  • java.lang.Runnable

  • Netflix Hystrix

  • javax.swing.Action

3. 解釋器(Interpreter)

Intent

為語(yǔ)言創(chuàng)建解釋器,通常由語(yǔ)言的語(yǔ)法和語(yǔ)法分析來定義。

Class Diagram

  • TerminalExpression:終結(jié)符表達(dá)式,每個(gè)終結(jié)符都需要一個(gè) TerminalExpression。

  • Context:上下文,包含解釋器之外的一些全局信息。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

以下是一個(gè)規(guī)則檢驗(yàn)器實(shí)現(xiàn),具有 and 和 or 規(guī)則,通過規(guī)則可以構(gòu)建一顆解析樹,用來檢驗(yàn)一個(gè)文本是否滿足解析樹定義的規(guī)則。

例如一顆解析樹為 D And (A Or (B C)),文本 "D A" 滿足該解析樹定義的規(guī)則。

這里的 Context 指的是 String。

public?abstract?class?Expression?{
????public?abstract?boolean?interpret(String?str);}public?class?TerminalExpression?extends?Expression?{

????private?String?literal?=?null;

????public?TerminalExpression(String?str)?{
????????literal?=?str;
????}

????public?boolean?interpret(String?str)?{
????????StringTokenizer?st?=?new?StringTokenizer(str);
????????while?(st.hasMoreTokens())?{
????????????String?test?=?st.nextToken();
????????????if?(test.equals(literal))?{
????????????????return?true;
????????????}
????????}
????????return?false;
????}}public?class?AndExpression?extends?Expression?{

????private?Expression?expression1?=?null;
????private?Expression?expression2?=?null;

????public?AndExpression(Expression?expression1,?Expression?expression2)?{
????????this.expression1?=?expression1;
????????this.expression2?=?expression2;
????}

????public?boolean?interpret(String?str)?{
????????return?expression1.interpret(str)?&&?expression2.interpret(str);
????}}public?class?OrExpression?extends?Expression?{
????private?Expression?expression1?=?null;
????private?Expression?expression2?=?null;

????public?OrExpression(Expression?expression1,?Expression?expression2)?{
????????this.expression1?=?expression1;
????????this.expression2?=?expression2;
????}

????public?boolean?interpret(String?str)?{
????????return?expression1.interpret(str)?||?expression2.interpret(str);
????}}public?class?Client?{

????/**?????*?構(gòu)建解析樹?????*/
????public?static?Expression?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?=?new?OrExpression(terminal2,?terminal3);
????????//?A?Or?(B?C)????????Expression?alternation2?=?new?OrExpression(terminal1,?alternation1);
????????//?D?And?(A?Or?(B?C))????????return?new?AndExpression(terminal4,?alternation2);
????}

????public?static?void?main(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));
????}}truefalse

JDK

  • java.util.Pattern

  • java.text.Normalizer

  • All subclasses of?java.text.Format

  • javax.el.ELResolver

4. 迭代器(Iterator)

Intent

提供一種順序訪問聚合對(duì)象元素的方法,并且不暴露聚合對(duì)象的內(nèi)部表示。

Class Diagram

  • Aggregate 是聚合類,其中 createIterator() 方法可以產(chǎn)生一個(gè) Iterator;

  • Iterator 主要定義了 hasNext() 和 next() 方法。

  • Client 組合了 Aggregate,為了迭代遍歷 Aggregate,也需要組合 Iterator。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

public?interface?Aggregate?{
????Iterator?createIterator();}public?class?ConcreteAggregate?implements?Aggregate?{

????private?Integer[]?items;

????public?ConcreteAggregate()?{
????????items?=?new?Integer[10];
????????for?(int?i?=?0;?i?<?items.length;?i++)?{
????????????items[i]?=?i;
????????}
????}

????@Override
????public?Iterator?createIterator()?{
????????return?new?ConcreteIterator<Integer>(items);
????}}public?interface?Iterator<Item>?{

????Item?next();

????boolean?hasNext();}public?class?ConcreteIterator<Item>?implements?Iterator?{

????private?Item[]?items;
????private?int?position?=?0;

????public?ConcreteIterator(Item[]?items)?{
????????this.items?=?items;
????}

????@Override
????public?Object?next()?{
????????return?items[position++];
????}

????@Override
????public?boolean?hasNext()?{
????????return?position?<?items.length;
????}}public?class?Client?{

????public?static?void?main(String[]?args)?{
????????Aggregate?aggregate?=?new?ConcreteAggregate();
????????Iterator<Integer>?iterator?=?aggregate.createIterator();
????????while?(iterator.hasNext())?{
????????????System.out.println(iterator.next());
????????}
????}}

JDK

  • java.util.Iterator

  • java.util.Enumeration

5. 中介者(Mediator)

Intent

集中相關(guān)對(duì)象之間復(fù)雜的溝通和控制方式。

Class Diagram

  • Mediator:中介者,定義一個(gè)接口用于與各同事(Colleague)對(duì)象通信。

  • Colleague:同事,相關(guān)對(duì)象


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

Alarm(鬧鐘)、CoffeePot(咖啡壺)、Calendar(日歷)、Sprinkler(噴頭)是一組相關(guān)的對(duì)象,在某個(gè)對(duì)象的事件產(chǎn)生時(shí)需要去操作其它對(duì)象,形成了下面這種依賴結(jié)構(gòu):


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



使用中介者模式可以將復(fù)雜的依賴結(jié)構(gòu)變成星形結(jié)構(gòu):


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



public?abstract?class?Colleague?{
????public?abstract?void?onEvent(Mediator?mediator);}public?class?Alarm?extends?Colleague?{

????@Override
????public?void?onEvent(Mediator?mediator)?{
????????mediator.doEvent("alarm");
????}

????public?void?doAlarm()?{
????????System.out.println("doAlarm()");
????}}public?class?CoffeePot?extends?Colleague?{
????@Override
????public?void?onEvent(Mediator?mediator)?{
????????mediator.doEvent("coffeePot");
????}

????public?void?doCoffeePot()?{
????????System.out.println("doCoffeePot()");
????}}public?class?Calender?extends?Colleague?{
????@Override
????public?void?onEvent(Mediator?mediator)?{
????????mediator.doEvent("calender");
????}

????public?void?doCalender()?{
????????System.out.println("doCalender()");
????}}public?class?Sprinkler?extends?Colleague?{
????@Override
????public?void?onEvent(Mediator?mediator)?{
????????mediator.doEvent("sprinkler");
????}

????public?void?doSprinkler()?{
????????System.out.println("doSprinkler()");
????}}public?abstract?class?Mediator?{
????public?abstract?void?doEvent(String?eventType);}public?class?ConcreteMediator?extends?Mediator?{
????private?Alarm?alarm;
????private?CoffeePot?coffeePot;
????private?Calender?calender;
????private?Sprinkler?sprinkler;

????public?ConcreteMediator(Alarm?alarm,?CoffeePot?coffeePot,?Calender?calender,?Sprinkler?sprinkler)?{
????????this.alarm?=?alarm;
????????this.coffeePot?=?coffeePot;
????????this.calender?=?calender;
????????this.sprinkler?=?sprinkler;
????}

????@Override
????public?void?doEvent(String?eventType)?{
????????switch?(eventType)?{
????????????case?"alarm":
????????????????doAlarmEvent();
????????????????break;
????????????case?"coffeePot":
????????????????doCoffeePotEvent();
????????????????break;
????????????case?"calender":
????????????????doCalenderEvent();
????????????????break;????????????default:
????????????????doSprinklerEvent();
????????}
????}

????public?void?doAlarmEvent()?{
????????alarm.doAlarm();
????????coffeePot.doCoffeePot();
????????calender.doCalender();
????????sprinkler.doSprinkler();
????}

????public?void?doCoffeePotEvent()?{
????????//?...????}

????public?void?doCalenderEvent()?{
????????//?...????}

????public?void?doSprinklerEvent()?{
????????//?...????}}public?class?Client?{
????public?static?void?main(String[]?args)?{
????????Alarm?alarm?=?new?Alarm();
????????CoffeePot?coffeePot?=?new?CoffeePot();
????????Calender?calender?=?new?Calender();
????????Sprinkler?sprinkler?=?new?Sprinkler();
????????Mediator?mediator?=?new?ConcreteMediator(alarm,?coffeePot,?calender,?sprinkler);
????????//?鬧鐘事件到達(dá),調(diào)用中介者就可以操作相關(guān)對(duì)象????????alarm.onEvent(mediator);
????}}doAlarm()doCoffeePot()doCalender()doSprinkler()

JDK

  • All scheduleXXX() methods of?java.util.Timer

  • java.util.concurrent.Executor#execute()

  • submit() and invokeXXX() methods of?java.util.concurrent.ExecutorService

  • scheduleXXX() methods of?java.util.concurrent.ScheduledExecutorService

  • java.lang.reflect.Method#invoke()

6. 備忘錄(Memento)

Intent

在不違反封裝的情況下獲得對(duì)象的內(nèi)部狀態(tài),從而在需要時(shí)可以將對(duì)象恢復(fù)到最初狀態(tài)。

Class Diagram

  • Originator:原始對(duì)象

  • Caretaker:負(fù)責(zé)保存好備忘錄

  • Menento:備忘錄,存儲(chǔ)原始對(duì)象的的狀態(tài)。備忘錄實(shí)際上有兩個(gè)接口,一個(gè)是提供給 Caretaker 的窄接口:它只能將備忘錄傳遞給其它對(duì)象;一個(gè)是提供給 Originator 的寬接口,允許它訪問到先前狀態(tài)所需的所有數(shù)據(jù)。理想情況是只允許 Originator 訪問本備忘錄的內(nèi)部狀態(tài)。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

以下實(shí)現(xiàn)了一個(gè)簡(jiǎn)單計(jì)算器程序,可以輸入兩個(gè)值,然后計(jì)算這兩個(gè)值的和。備忘錄模式允許將這兩個(gè)值存儲(chǔ)起來,然后在某個(gè)時(shí)刻用存儲(chǔ)的狀態(tài)進(jìn)行恢復(fù)。

實(shí)現(xiàn)參考:Memento Pattern - Calculator Example - Java Sourcecode

/**?*?Originator?Interface?*/public?interface?Calculator?{

????//?Create?Memento????PreviousCalculationToCareTaker?backupLastCalculation();

????//?setMemento????void?restorePreviousCalculation(PreviousCalculationToCareTaker?memento);

????int?getCalculationResult();

????void?setFirstNumber(int?firstNumber);

????void?setSecondNumber(int?secondNumber);}/**?*?Originator?Implementation?*/public?class?CalculatorImp?implements?Calculator?{

????private?int?firstNumber;
????private?int?secondNumber;

????@Override
????public?PreviousCalculationToCareTaker?backupLastCalculation()?{
????????//?create?a?memento?object?used?for?restoring?two?numbers????????return?new?PreviousCalculationImp(firstNumber,?secondNumber);
????}

????@Override
????public?void?restorePreviousCalculation(PreviousCalculationToCareTaker?memento)?{
????????this.firstNumber?=?((PreviousCalculationToOriginator)?memento).getFirstNumber();
????????this.secondNumber?=?((PreviousCalculationToOriginator)?memento).getSecondNumber();
????}

????@Override
????public?int?getCalculationResult()?{
????????//?result?is?adding?two?numbers????????return?firstNumber?+?secondNumber;
????}

????@Override
????public?void?setFirstNumber(int?firstNumber)?{
????????this.firstNumber?=?firstNumber;
????}

????@Override
????public?void?setSecondNumber(int?secondNumber)?{
????????this.secondNumber?=?secondNumber;
????}}/**?*?Memento?Interface?to?Originator?*?*?This?interface?allows?the?originator?to?restore?its?state?*/public?interface?PreviousCalculationToOriginator?{
????int?getFirstNumber();
????int?getSecondNumber();}/**?*??Memento?interface?to?CalculatorOperator?(Caretaker)?*/public?interface?PreviousCalculationToCareTaker?{
????//?no?operations?permitted?for?the?caretaker}/**?*?Memento?Object?Implementation?*?<p>?*?Note?that?this?object?implements?both?interfaces?to?Originator?and?CareTaker?*/public?class?PreviousCalculationImp?implements?PreviousCalculationToCareTaker,
????????PreviousCalculationToOriginator?{

????private?int?firstNumber;
????private?int?secondNumber;

????public?PreviousCalculationImp(int?firstNumber,?int?secondNumber)?{
????????this.firstNumber?=?firstNumber;
????????this.secondNumber?=?secondNumber;
????}

????@Override
????public?int?getFirstNumber()?{
????????return?firstNumber;
????}

????@Override
????public?int?getSecondNumber()?{
????????return?secondNumber;
????}}/**?*?CareTaker?object?*/public?class?Client?{

????public?static?void?main(String[]?args)?{
????????//?program?starts????????Calculator?calculator?=?new?CalculatorImp();

????????//?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-273110

JDK

  • java.io.Serializable

7. 觀察者(Observer)

Intent

定義對(duì)象之間的一對(duì)多依賴,當(dāng)一個(gè)對(duì)象狀態(tài)改變時(shí),它的所有依賴都會(huì)收到通知并且自動(dòng)更新狀態(tài)。

主題(Subject)是被觀察的對(duì)象,而其所有依賴者(Observer)稱為觀察者。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Class Diagram

主題(Subject)具有注冊(cè)和移除觀察者、并通知所有觀察者的功能,主題是通過維護(hù)一張觀察者列表來實(shí)現(xiàn)這些操作的。

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


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

天氣數(shù)據(jù)布告板會(huì)在天氣信息發(fā)生改變時(shí)更新其內(nèi)容,布告板有多個(gè),并且在將來會(huì)繼續(xù)增加。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



public?interface?Subject?{
????void?registerObserver(Observer?o);

????void?removeObserver(Observer?o);

????void?notifyObserver();}public?class?WeatherData?implements?Subject?{
????private?List<Observer>?observers;
????private?float?temperature;
????private?float?humidity;
????private?float?pressure;

????public?WeatherData()?{
????????observers?=?new?ArrayList<>();
????}

????public?void?setMeasurements(float?temperature,?float?humidity,?float?pressure)?{
????????this.temperature?=?temperature;
????????this.humidity?=?humidity;
????????this.pressure?=?pressure;
????????notifyObserver();
????}

????@Override
????public?void?registerObserver(Observer?o)?{
????????observers.add(o);
????}

????@Override
????public?void?removeObserver(Observer?o)?{
????????int?i?=?observers.indexOf(o);
????????if?(i?>=?0)?{
????????????observers.remove(i);
????????}
????}

????@Override
????public?void?notifyObserver()?{
????????for?(Observer?o?:?observers)?{
????????????o.update(temperature,?humidity,?pressure);
????????}
????}}public?interface?Observer?{
????void?update(float?temp,?float?humidity,?float?pressure);}public?class?StatisticsDisplay?implements?Observer?{

????public?StatisticsDisplay(Subject?weatherData)?{
????????weatherData.reisterObserver(this);
????}

????@Override
????public?void?update(float?temp,?float?humidity,?float?pressure)?{
????????System.out.println("StatisticsDisplay.update:?"?+?temp?+?"?"?+?humidity?+?"?"?+?pressure);
????}}public?class?CurrentConditionsDisplay?implements?Observer?{

????public?CurrentConditionsDisplay(Subject?weatherData)?{
????????weatherData.registerObserver(this);
????}

????@Override
????public?void?update(float?temp,?float?humidity,?float?pressure)?{
????????System.out.println("CurrentConditionsDisplay.update:?"?+?temp?+?"?"?+?humidity?+?"?"?+?pressure);
????}}public?class?WeatherStation?{
????public?static?void?main(String[]?args)?{
????????WeatherData?weatherData?=?new?WeatherData();
????????CurrentConditionsDisplay?currentConditionsDisplay?=?new?CurrentConditionsDisplay(weatherData);
????????StatisticsDisplay?statisticsDisplay?=?new?StatisticsDisplay(weatherData);

????????weatherData.setMeasurements(0,?0,?0);
????????weatherData.setMeasurements(1,?1,?1);
????}}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

  • java.util.Observer

  • java.util.EventListener

  • javax.servlet.http.HttpSessionBindingListener

  • RxJava

8. 狀態(tài)(State)

Intent

允許對(duì)象在內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來好像修改了它所屬的類。

Class Diagram


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

糖果銷售機(jī)有多種狀態(tài),每種狀態(tài)下銷售機(jī)有不同的行為,狀態(tài)可以發(fā)生轉(zhuǎn)移,使得銷售機(jī)的行為也發(fā)生改變。

Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)


public?interface?State?{
????/**?????*?投入?25?分錢?????*/
????void?insertQuarter();

????/**?????*?退回?25?分錢?????*/
????void?ejectQuarter();

????/**?????*?轉(zhuǎn)動(dòng)曲柄?????*/
????void?turnCrank();

????/**?????*?發(fā)放糖果?????*/
????void?dispense();}public?class?HasQuarterState?implements?State?{

????private?GumballMachine?gumballMachine;

????public?HasQuarterState(GumballMachine?gumballMachine)?{
????????this.gumballMachine?=?gumballMachine;
????}

????@Override
????public?void?insertQuarter()?{
????????System.out.println("You?can't?insert?another?quarter");
????}

????@Override
????public?void?ejectQuarter()?{
????????System.out.println("Quarter?returned");
????????gumballMachine.setState(gumballMachine.getNoQuarterState());
????}

????@Override
????public?void?turnCrank()?{
????????System.out.println("You?turned...");
????????gumballMachine.setState(gumballMachine.getSoldState());
????}

????@Override
????public?void?dispense()?{
????????System.out.println("No?gumball?dispensed");
????}}public?class?NoQuarterState?implements?State?{

????GumballMachine?gumballMachine;

????public?NoQuarterState(GumballMachine?gumballMachine)?{
????????this.gumballMachine?=?gumballMachine;
????}

????@Override
????public?void?insertQuarter()?{
????????System.out.println("You?insert?a?quarter");
????????gumballMachine.setState(gumballMachine.getHasQuarterState());
????}

????@Override
????public?void?ejectQuarter()?{
????????System.out.println("You?haven't?insert?a?quarter");
????}

????@Override
????public?void?turnCrank()?{
????????System.out.println("You?turned,?but?there's?no?quarter");
????}

????@Override
????public?void?dispense()?{
????????System.out.println("You?need?to?pay?first");
????}}public?class?SoldOutState?implements?State?{

????GumballMachine?gumballMachine;

????public?SoldOutState(GumballMachine?gumballMachine)?{
????????this.gumballMachine?=?gumballMachine;
????}

????@Override
????public?void?insertQuarter()?{
????????System.out.println("You?can't?insert?a?quarter,?the?machine?is?sold?out");
????}

????@Override
????public?void?ejectQuarter()?{
????????System.out.println("You?can't?eject,?you?haven't?inserted?a?quarter?yet");
????}

????@Override
????public?void?turnCrank()?{
????????System.out.println("You?turned,?but?there?are?no?gumballs");
????}

????@Override
????public?void?dispense()?{
????????System.out.println("No?gumball?dispensed");
????}}public?class?SoldState?implements?State?{

????GumballMachine?gumballMachine;

????public?SoldState(GumballMachine?gumballMachine)?{
????????this.gumballMachine?=?gumballMachine;
????}

????@Override
????public?void?insertQuarter()?{
????????System.out.println("Please?wait,?we're?already?giving?you?a?gumball");
????}

????@Override
????public?void?ejectQuarter()?{
????????System.out.println("Sorry,?you?already?turned?the?crank");
????}

????@Override
????public?void?turnCrank()?{
????????System.out.println("Turning?twice?doesn't?get?you?another?gumball!");
????}

????@Override
????public?void?dispense()?{
????????gumballMachine.releaseBall();
????????if?(gumballMachine.getCount()?>?0)?{
????????????gumballMachine.setState(gumballMachine.getNoQuarterState());
????????}?else?{
????????????System.out.println("Oops,?out?of?gumballs");
????????????gumballMachine.setState(gumballMachine.getSoldOutState());
????????}
????}}public?class?GumballMachine?{

????private?State?soldOutState;
????private?State?noQuarterState;
????private?State?hasQuarterState;
????private?State?soldState;

????private?State?state;
????private?int?count?=?0;

????public?GumballMachine(int?numberGumballs)?{
????????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?void?insertQuarter()?{
????????state.insertQuarter();
????}

????public?void?ejectQuarter()?{
????????state.ejectQuarter();
????}

????public?void?turnCrank()?{
????????state.turnCrank();
????????state.dispense();
????}

????public?void?setState(State?state)?{
????????this.state?=?state;
????}

????public?void?releaseBall()?{
????????System.out.println("A?gumball?comes?rolling?out?the?slot...");
????????if?(count?!=?0)?{
????????????count?-=?1;
????????}
????}

????public?State?getSoldOutState()?{
????????return?soldOutState;
????}

????public?State?getNoQuarterState()?{
????????return?noQuarterState;
????}

????public?State?getHasQuarterState()?{
????????return?hasQuarterState;
????}

????public?State?getSoldState()?{
????????return?soldState;
????}

????public?int?getCount()?{
????????return?count;
????}}public?class?Client?{

????public?static?void?main(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?quarterYou?turned...A?gumball?comes?rolling?out?the?slot...You?insert?a?quarterQuarter?returnedYou?turned,?but?there's?no?quarterYou?need?to?pay?firstYou?insert?a?quarterYou?turned...A?gumball?comes?rolling?out?the?slot...You?insert?a?quarterYou?turned...A?gumball?comes?rolling?out?the?slot...You?haven't?insert?a?quarterYou?insert?a?quarterYou?can't?insert?another?quarterYou?turned...A?gumball?comes?rolling?out?the?slot...You?insert?a?quarterYou?turned...A?gumball?comes?rolling?out?the?slot...Oops,?out?of?gumballsYou?can't?insert?a?quarter,?the?machine?is?sold?outYou?turned,?but?there?are?no?gumballsNo?gumball?dispensed

9. 策略(Strategy)

Intent

定義一系列算法,封裝每個(gè)算法,并使它們可以互換。

策略模式可以讓算法獨(dú)立于使用它的客戶端。

Class Diagram

  • Strategy 接口定義了一個(gè)算法族,它們都實(shí)現(xiàn)了 behavior() 方法。

  • Context 是使用到該算法族的類,其中的 doSomething() 方法會(huì)調(diào)用 behavior(),setStrategy(Strategy) 方法可以動(dòng)態(tài)地改變 strategy 對(duì)象,也就是說能動(dòng)態(tài)地改變 Context 所使用的算法。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



與狀態(tài)模式的比較

狀態(tài)模式的類圖和策略模式類似,并且都是能夠動(dòng)態(tài)改變對(duì)象的行為。但是狀態(tài)模式是通過狀態(tài)轉(zhuǎn)移來改變 Context 所組合的 State 對(duì)象,而策略模式是通過 Context 本身的決策來改變組合的 Strategy 對(duì)象。所謂的狀態(tài)轉(zhuǎn)移,是指 Context 在運(yùn)行過程中由于一些條件發(fā)生改變而使得 State 對(duì)象發(fā)生改變,注意必須要是在運(yùn)行過程中。

狀態(tài)模式主要是用來解決狀態(tài)轉(zhuǎn)移的問題,當(dāng)狀態(tài)發(fā)生轉(zhuǎn)移了,那么 Context 對(duì)象就會(huì)改變它的行為;而策略模式主要是用來封裝一組可以互相替代的算法族,并且可以根據(jù)需要?jiǎng)討B(tài)地去替換 Context 使用的算法。

Implementation

設(shè)計(jì)一個(gè)鴨子,它可以動(dòng)態(tài)地改變叫聲。這里的算法族是鴨子的叫聲行為。

public?interface?QuackBehavior?{
????void?quack();}public?class?Quack?implements?QuackBehavior?{
????@Override
????public?void?quack()?{
????????System.out.println("quack!");
????}}public?class?Squeak?implements?QuackBehavior{
????@Override
????public?void?quack()?{
????????System.out.println("squeak!");
????}}public?class?Duck?{

????private?QuackBehavior?quackBehavior;

????public?void?performQuack()?{
????????if?(quackBehavior?!=?null)?{
????????????quackBehavior.quack();
????????}
????}

????public?void?setQuackBehavior(QuackBehavior?quackBehavior)?{
????????this.quackBehavior?=?quackBehavior;
????}}public?class?Client?{

????public?static?void?main(String[]?args)?{
????????Duck?duck?=?new?Duck();
????????duck.setQuackBehavior(new?Squeak());
????????duck.performQuack();
????????duck.setQuackBehavior(new?Quack());
????????duck.performQuack();
????}}squeak!quack!

JDK

  • java.util.Comparator#compare()

  • javax.servlet.http.HttpServlet

  • javax.servlet.Filter#doFilter()

10. 模板方法(Template Method)

Intent

定義算法框架,并將一些步驟的實(shí)現(xiàn)延遲到子類。

通過模板方法,子類可以重新定義算法的某些步驟,而不用改變算法的結(jié)構(gòu)。

Class Diagram


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

沖咖啡和沖茶都有類似的流程,但是某些步驟會(huì)有點(diǎn)不一樣,要求復(fù)用那些相同步驟的代碼。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



public?abstract?class?CaffeineBeverage?{

????final?void?prepareRecipe()?{
????????boilWater();
????????brew();
????????pourInCup();
????????addCondiments();
????}

????abstract?void?brew();

????abstract?void?addCondiments();

????void?boilWater()?{
????????System.out.println("boilWater");
????}

????void?pourInCup()?{
????????System.out.println("pourInCup");
????}}public?class?Coffee?extends?CaffeineBeverage?{
????@Override
????void?brew()?{
????????System.out.println("Coffee.brew");
????}

????@Override
????void?addCondiments()?{
????????System.out.println("Coffee.addCondiments");
????}}public?class?Tea?extends?CaffeineBeverage?{
????@Override
????void?brew()?{
????????System.out.println("Tea.brew");
????}

????@Override
????void?addCondiments()?{
????????System.out.println("Tea.addCondiments");
????}}public?class?Client?{
????public?static?void?main(String[]?args)?{
????????CaffeineBeverage?caffeineBeverage?=?new?Coffee();
????????caffeineBeverage.prepareRecipe();
????????System.out.println("-----------");
????????caffeineBeverage?=?new?Tea();
????????caffeineBeverage.prepareRecipe();
????}}boilWaterCoffee.brewpourInCupCoffee.addCondiments-----------boilWaterTea.brewpourInCupTea.addCondiments

JDK

  • java.util.Collections#sort()

  • java.io.InputStream#skip()

  • java.io.InputStream#read()

  • java.util.AbstractList#indexOf()

11. 訪問者(Visitor)

Intent

為一個(gè)對(duì)象結(jié)構(gòu)(比如組合結(jié)構(gòu))增加新能力。

Class Diagram

  • Visitor:訪問者,為每一個(gè) ConcreteElement 聲明一個(gè) visit 操作

  • ConcreteVisitor:具體訪問者,存儲(chǔ)遍歷過程中的累計(jì)結(jié)果

  • ObjectStructure:對(duì)象結(jié)構(gòu),可以是組合結(jié)構(gòu),或者是一個(gè)集合。


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

public?interface?Element?{
????void?accept(Visitor?visitor);}class?CustomerGroup?{

????private?List<Customer>?customers?=?new?ArrayList<>();

????void?accept(Visitor?visitor)?{
????????for?(Customer?customer?:?customers)?{
????????????customer.accept(visitor);
????????}
????}

????void?addCustomer(Customer?customer)?{
????????customers.add(customer);
????}}public?class?Customer?implements?Element?{

????private?String?name;
????private?List<Order>?orders?=?new?ArrayList<>();

????Customer(String?name)?{
????????this.name?=?name;
????}

????String?getName()?{
????????return?name;
????}

????void?addOrder(Order?order)?{
????????orders.add(order);
????}

????public?void?accept(Visitor?visitor)?{
????????visitor.visit(this);
????????for?(Order?order?:?orders)?{
????????????order.accept(visitor);
????????}
????}}public?class?Order?implements?Element?{

????private?String?name;
????private?List<Item>?items?=?new?ArrayList();

????Order(String?name)?{
????????this.name?=?name;
????}

????Order(String?name,?String?itemName)?{
????????this.name?=?name;
????????this.addItem(new?Item(itemName));
????}

????String?getName()?{
????????return?name;
????}

????void?addItem(Item?item)?{
????????items.add(item);
????}

????public?void?accept(Visitor?visitor)?{
????????visitor.visit(this);

????????for?(Item?item?:?items)?{
????????????item.accept(visitor);
????????}
????}}public?class?Item?implements?Element?{

????private?String?name;

????Item(String?name)?{
????????this.name?=?name;
????}

????String?getName()?{
????????return?name;
????}

????public?void?accept(Visitor?visitor)?{
????????visitor.visit(this);
????}}public?interface?Visitor?{
????void?visit(Customer?customer);

????void?visit(Order?order);

????void?visit(Item?item);}public?class?GeneralReport?implements?Visitor?{

????private?int?customersNo;
????private?int?ordersNo;
????private?int?itemsNo;

????public?void?visit(Customer?customer)?{
????????System.out.println(customer.getName());
????????customersNo++;
????}

????public?void?visit(Order?order)?{
????????System.out.println(order.getName());
????????ordersNo++;
????}

????public?void?visit(Item?item)?{
????????System.out.println(item.getName());
????????itemsNo++;
????}

????public?void?displayResults()?{
????????System.out.println("Number?of?customers:?"?+?customersNo);
????????System.out.println("Number?of?orders:????"?+?ordersNo);
????????System.out.println("Number?of?items:?????"?+?itemsNo);
????}}public?class?Client?{
????public?static?void?main(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?=?new?CustomerGroup();
????????customers.addCustomer(customer1);
????????customers.addCustomer(customer2);

????????GeneralReport?visitor?=?new?GeneralReport();
????????customers.accept(visitor);
????????visitor.displayResults();
????}}customer1order1item1order2item1order3item1customer2order_aitem_a1item_a2item_a3Number?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. 空對(duì)象(Null)

Intent

使用什么都不做的空對(duì)象來代替 NULL。

一個(gè)方法返回 NULL,意味著方法的調(diào)用端需要去檢查返回值是否是 NULL,這么做會(huì)導(dǎo)致非常多的冗余的檢查代碼。并且如果某一個(gè)調(diào)用端忘記了做這個(gè)檢查返回值,而直接使用返回的對(duì)象,那么就有可能拋出空指針異常。

Class Diagram


Java的23種設(shè)計(jì)模式,詳細(xì)講解(二)



Implementation

public?abstract?class?AbstractOperation?{
????abstract?void?request();}public?class?RealOperation?extends?AbstractOperation?{
????@Override
????void?request()?{
????????System.out.println("do?something");
????}}public?class?NullOperation?extends?AbstractOperation{
????@Override
????void?request()?{
????????//?do?nothing????}}public?class?Client?{
????public?static?void?main(String[]?args)?{
????????AbstractOperation?abstractOperation?=?func(-1);
????????abstractOperation.request();
????}

????public?static?AbstractOperation?func(int?para)?{
????????if?(para?<?0)?{
????????????return?new?NullOperation();
????????}
????????return?new?RealOperation();
????}}


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI