關注公眾號獲取更多資料

設計模式— 行為型模式
? 行為型模式描述的死程式運行時復雜的流程控制,描述了多個類或者物件之間怎樣相互協調合作,涉及演算法與物件之間的職責分配,
? 行為型模式是23中設計模式中最為龐大的,包括以下11中:
@
目錄- 設計模式— 行為型模式
- 模板方法模式(Template Method)
- 策略模式(Strategy)
- 命令模式(Command)
- 職責鏈模式(Chain of Responsibility)
- 狀態模式(State)
- 觀察者模式(Observer)
- 中介者模式(Mediator)
- 迭代器模式(Iterator)
- 訪問者模式(Visitor)
- 備忘錄模式(Memento)
- 解釋器模式(Interpreter)
模板方法模式(Template Method)
定義:模板方法定義一個操作中的演算法骨架,將演算法中的一些步驟延遲到子類中去,是的子類可以在不改變原有演算法結構的情況下重新定義這些演算法步驟,
? 模板方法模式主要包含一下幾種結構:
-
抽象類:定義一個演算法的輪廓和骨架
- 模板方法:定義演算法骨架,按照某種順序呼叫其他方法,
- 基本方法:演算法中的基本步驟,
- 抽象方法:需要由子類實作的方法,
- 具體方法:在抽象類中已經實作的方法,子類可以重寫或繼承他,
- 鉤子方法:抽象類中實作,主要用來判斷是否要使用子類重寫的方法,
-
具體子類:繼承了抽象類并實作抽象方法,
? 根據以上角色結構可以大致畫出如下類圖:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rFBPCtnG-1604422914903)(行為型模式.assets/模板方法模式.png)]](https://img-blog.csdnimg.cn/20201104010218935.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 舉例說明:五一小長假出去旅游,需要選擇地點,然后預定計劃,最后選擇出行方式,出行方式可是飛機,火車或者自駕游等,在這里選擇地點,定計劃,選擇出行方式可以理解為模板方法,選擇出行方式是抽象方法,判斷出行方式為鉤子方法,定計劃步驟可以作為具體方法實作,
? 代碼如下:
- 抽象類
//抽象類
abstract class Travel {
protected String destinate;
//模板方法
protected Travel(String destinate) {
System.out.println("去"+destinate+"...");
this.destinate = destinate;
}
public void travel() {
plan();
if (travelHook()) {
byTicket();
} else {
byCar();
}
}
//具體方法
protected void plan() {
System.out.println("預定計劃...");
}
//鉤子方法
protected boolean travelHook() {
return "beijing".equals(this.destinate);
}
//抽象方法
abstract void byTicket();
protected void byCar() {
System.out.println("自駕游...");
}
}
- 具體子類
//具體子類
class Beijing extends Travel {
public Beijing(String destinate) {
super(destinate);
}
@Override
void byTicket() {
System.out.println("買飛機票...");
}
}
//具體子類
class Shanghai extends Travel{
public Shanghai(String destinate)
{
super(destinate);
}
@Override
void byTicket() {
}
}
- 測驗
Travel beijing = new Beijing("beijing");
beijing.travel();
Travel shanghai = new Shanghai("shanghai");
shanghai.travel();
- 輸出結果
去beijing...
預定計劃...
買飛機票...
去shanghai...
預定計劃...
自駕游...
策略模式(Strategy)
? 定義:定義了一系列演算法,并將每個演算法封裝起來,使之可以相互替代,并且演算法的改變不會影響到使用者,
? 策略模式的結構如下:
- 抽象策略:定義了一個公共介面,每個演算法可以實作這個介面,實作呼叫方式的統一,
- 具體策略:實作抽象策略的捷庫,提供具體的演算法,
- 環境類:擁有一個策略類的參考,最終給客戶端呼叫,
? 根據以上結構可以畫出如下類圖:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yBNra33t-1604422914905)(行為型模式.assets/策略模式1.png)]](https://img-blog.csdnimg.cn/20201104010237833.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 模式的實作:
- 抽象策略
//抽象策略類
interface Strategy {
void execute();
}
- 具體策略
//具體策略類
class StrategyA implements Strategy {
@Override
public void execute() {
System.out.println("do as strategyA...");
}
}
//具體策略類
class StrategyB implements Strategy {
@Override
public void execute() {
System.out.println("do as strategyB...");
}
}
- 環境類
//環境類
class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeMethod() {
this.strategy.execute();
}
}
- 客戶端
Context context = new Context();
context.setStrategy(new StrategyA());
context.executeMethod();//do as strategyA...
context.setStrategy(new StrategyB());
context.executeMethod();//do as strategyB...
? 對于一個龐大的系統來說,通常情況下會有很多策略,此時如果直接使用原始的策略模式將會對策略的管理顯得例外困難,將策略模式與工廠模式相結合而成的策略工廠模式將會使得對策略的管理更加方便,升級后的類圖如下,代碼比較簡單,不做過多詳解,
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xkkjZ64e-1604422914906)(行為型模式.assets/策略模式2.png)]](https://img-blog.csdnimg.cn/20201104010251715.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
命令模式(Command)
? 定義:將一個請求封裝成一個物件,使發出的請求的責任和執行請求的責任分割開,
? 命令模式在平時生活中有很多場景,比如去餐廳吃飯,點餐時點的不同的菜品相當于多個請求,隨后這多個不同的菜會到廚房分發給不同的廚師,此時相當于執行請求的角色,在這個場景中就使得請求和執行分割,我們點菜的人并不知道廚房具體是如何執行的,
? 命令模式結構:
- 抽象命令類:宣告執行命令的介面,擁有執行命令的抽象方法,
- 具體命令角色:實作抽象命令類,通過呼叫實作者/接收者完成命令的執行操作,
- 實作者/操作者:實作具體命令的執行操作,
- 呼叫者/請求者:請求的發送者,一般呼叫命令角色,不直接呼叫實作者/操作者,
? 類結構如下:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-brZPxoGq-1604422914907)(行為型模式.assets/命令模式1.png)]](https://img-blog.csdnimg.cn/20201104010303861.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 模式實作:
- 抽象命令角色
//抽象命令角色
interface ICommand {
void execute();
}
- 具體命令角色
//具體命令角色
class CommandA implements ICommand {
private ReceiverA receiver;
public CommandA() {
receiver = new ReceiverA();
}
@Override
public void execute() {
receiver.action();
}
}
//具體命令角色
class CommandB implements ICommand {
private ReceiverB receiver;
public CommandB() {
receiver = new ReceiverB();
}
@Override
public void execute() {
receiver.action();
}
}
- 請求者
//請求者
class Invoker {
private ICommand cmd;
public Invoker(ICommand cmd) {
this.cmd = cmd;
}
public void call() {
cmd.execute();
}
}
- 測驗
new Invoker(new CommandA()).call();//receiverA do...
new Invoker(new CommandB()).call();//receiverB do...
? 通常情況下,一個請求需要多個接受者去完成,此時可以將命令模式和之前的組合模式相結合,組成宏命令模式又叫組合命令模式,具體類圖如下,代碼詳見文章尾的GitHub地址,
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-G7DfRqoB-1604422914909)(行為型模式.assets/命令模式2.png)]](https://img-blog.csdnimg.cn/20201104010319196.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
職責鏈模式(Chain of Responsibility)
? 定義:為避免請求發送者與多個請求處理者耦合在一起,將所有的請求處理者通過一個物件記住下一個物件的參考而形成一條鏈式結構;當有請求發生時,請求將沿著這條鏈傳遞,直到有物件處理它為止,
? 例如公司請假,請假三天以上和三天以內的審批人不同,如果將所有的審批人都依賴于請求者,那么請求者中都需要依賴所有的審批人物件,如果將請假請求沿著審批人的鏈一個個傳遞下去,直到有人審批或者拒絕,請求停止,此時請求者物件只需要依賴一個審批人物件,從一定程度上降低了耦合,
? 模式結構:
- 抽象處理者:定義一個處理請求的介面,包含抽象方法和一個后繼鏈接,
- 具體處理者:實作抽象處理者的處理方法,并判斷是否能處理當前請求,如果不能則將請求傳遞給下一個處理者,
- 客戶類:創建處理鏈接,并向鏈頭提交請求,
? 類結構:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ytIDdyt5-1604422914910)(行為型模式.assets/責任鏈模式.png)]](https://img-blog.csdnimg.cn/20201104010333428.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 模式實作:
- 抽象處理者
//抽象處理者
abstract class IHandler {
private IHandler next;
abstract void execute(String key);
public void setNext(IHandler next) {
this.next = next;
}
public IHandler getNext() {
return this.next;
}
}
- 具體處理者
//具體處理者
class HandlerA extends IHandler {
@Override
void execute(String key) {
if ("a".equals(key)) {
System.out.println("handlerA do....");
return;
}
if (this.getNext() != null) {
this.getNext().execute(key);
return;
}
System.out.println("請求未處理...");
}
}
//具體處理者
class HandlerB extends IHandler {
@Override
void execute(String key) {
if ("b".equals(key)) {
System.out.println("handlerB do....");
return;
}
if (this.getNext() != null) {
this.getNext().execute(key);
return;
}
System.out.println("請求未處理...");
}
}
- 客戶類
IHandler handlerA = new HandlerA();
IHandler handlerB = new HandlerB();
handlerA.setNext(handlerB);
handlerA.execute("a");//handlerA do....
handlerA.execute("b");//handlerB do....
handlerA.execute("c");//請求未處理...
狀態模式(State)
? 定義:對有狀態的物件,把復雜的判斷邏輯提取到不同的物件中,允許物件再起內部狀態發生變化時改變其行為,
? 模式結構:
- 環境角色:定義客戶感興趣的介面,維護一個當前狀態,并將與狀態相關的操作委托給當前狀態物件處理,
- 抽象狀態:定義介面,統一具體狀態的行為準則,
- 具體狀態:實作抽象狀態對應的行為,
? 類結構:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fkM8ir9U-1604422914911)(行為型模式.assets/狀態模式.png)]](https://img-blog.csdnimg.cn/20201104010346947.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 舉例說明:多執行緒在執行程序中可以存在多個狀態,可以簡單的使用狀態模式設計一個多執行緒的狀態轉換程式,代碼如下:
- 抽象角色
//抽象狀態
interface IThreadState {
void execute();
}
- 具體狀態
//具體狀態
class New implements IThreadState {
@Override
public void execute() {
System.out.println("thread new...");
}
}
//具體狀態
class Runnable implements IThreadState {
@Override
public void execute() {
System.out.println("thread runnable...");
}
}
//具體狀態
class Running implements IThreadState {
@Override
public void execute() {
System.out.println("thread running...");
}
}
//具體狀態
class Dead implements IThreadState {
@Override
public void execute() {
System.out.println("thread dead...");
}
}
- 環境角色
//環境角色
class ThreadContext {
private IThreadState state;
public void start() {
this.state = new New();
this.state.execute();
}
public void runnable() {
this.state = new Runnable();
this.state.execute();
}
public void runnung() {
this.state = new Running();
this.state.execute();
}
public void stop() {
this.state = new Dead();
this.state.execute();
}
}
- 測驗
ThreadContext context = new ThreadContext();
context.start();//thread new...
context.runnable();//thread runnable...
context.runnung();//thread running...
context.stop();//thread dead...
? 很多情況下,可能有多個環境享用一組狀態,此時可以將狀態模式和享元模式結合起來使用,在環境類中儲存共享的狀態,
觀察者模式(Observer)
? 定義:多個物件之間存在一對多的依賴關系,當一個物件的狀態發生改變時,所有依賴于他的物件都會得到通知并自動更新,
? 模式結構:
- 抽象主題:提供了保存觀察者物件的聚集類,包括增加和減少觀察者的方法以及通知方法等,
- 具體主題:繼承抽象主題,實作抽象主題中的通知方法,
- 抽象觀察者:一個介面,定義了更新的方法,
- 具體觀察者:實作了抽象觀察者中的更新方法,
? 注意:實作觀察者模式時,具體目標和具體觀察者之間不能直接呼叫,否則兩者之間將緊密耦合在一起,違反了面對物件的設計原則,
? 類結構:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ZYX3rBF0-1604422914913)(行為型模式.assets/觀察者模式.png)]](https://img-blog.csdnimg.cn/20201104010402579.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 代碼實作:
- 抽象觀察者
//抽象觀察者
interface IObserver {
void execute();
}
- 具體觀察者
//具體觀察者
class ObserverA implements IObserver {
@Override
public void execute() {
System.out.println("observerA get...");
}
}
//具體觀察者
class ObserverB implements IObserver {
@Override
public void execute() {
System.out.println("observerB get...");
}
}
- 抽象主題
//抽象主題
abstract class Subject {
protected List<IObserver> observers = new ArrayList<>();
public void regiest(IObserver observer) {
observers.add(observer);
}
public void remove(IObserver observer) {
observers.remove(observer);
}
abstract void notifyObservers();
}
- 具體主題
//具體主題
class ConcreteSubject extends Subject {
@Override
void notifyObservers() {
for (IObserver observer : observers) {
observer.execute();
}
}
}
- 測驗
Subject subject = new ConcreteSubject();
subject.regiest(new ObserverA());
subject.regiest(new ObserverB());
subject.notifyObservers();
//observerA get...
//observerB get...
? Java中通過java.util.Observable(抽象目標)和java.util.Observer(抽象觀察者)定義了觀察者模式,只要實作他們就可以撰寫觀察者模式實體,
中介者模式(Mediator)
? 定義:定義一個中介物件來封裝一系列物件之間的互動,使原有物件之間的耦合松散,并且可以獨立的改變他們之間的互動,
? 模式結構:
- 抽象中介者:中介者的介面,定義了物件轉發,注冊等介面,
- 具體中介者,實作中介者介面,定義一個list管理同事物件,
- 抽象同事類:定義同事類介面,保存中介者物件,
- 具體同事類:抽象同事類的實作類,
? 類結構:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PQGFq0fK-1604422914914)(行為型模式.assets/中介者模式.png)]](https://img-blog.csdnimg.cn/20201104010418268.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 代碼實作:
- 抽象中介者
//抽象中介者
interface Mediator {
void register(Colleague colleague);
void relay(Colleague colleague);
}
- 抽象同事類
//抽象同事類
abstract class Colleague {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
abstract void receive();
abstract void send();
}
- 具體同事類
//具體同事類
class ColleagueA extends Colleague {
@Override
void receive() {
System.out.println("colleagueA received...");
}
@Override
void send() {
System.out.println("colleagueA send...");
mediator.relay(this);//請求中介者轉發
}
}
//具體同事類
class ColleagueB extends Colleague {
@Override
void receive() {
System.out.println("colleagueB received...");
}
@Override
void send() {
System.out.println("colleagueB send...");
mediator.relay(this);//請求中介者轉發
}
}
- 具體中介者
//具體中介者
class ConcreteMediator implements Mediator {
private List<Colleague> colleagus = new ArrayList<>();
@Override
public void register(Colleague colleague) {
colleagus.add(colleague);
colleague.setMediator(this);
}
@Override
public void relay(Colleague colleague) {
for (Colleague co : colleagus) {
if (!co.equals(colleague)) {
co.receive();
}
}
}
}
- 測驗
Mediator mediator = new ConcreteMediator();
Colleague a = new ColleagueA();
Colleague b = new ColleagueB();
mediator.register(a);
mediator.register(b);
a.send();
b.send();
//colleagueA send...
//colleagueB received...
//colleagueB send...
//colleagueA received...
? 觀察者模式和中介者模式功能很類似,都是一個物件改變狀態通知其他物件,不同的是,觀察者擁有所有被觀察物件的所有參考,通過介面型別依賴,而中介者模式,變化的物件不能直接與被通知的物件直接聯系,他不知道到底有多少物件被通知了,而是通過第三方進行操作,
? 具體內容可以參考:http://www.sohu.com/a/207062452_464084
迭代器模式(Iterator)
? 定義:提供一個物件來順序訪問聚合物件中的一系列資料,二部暴露聚合物件的內部表示,
? 模式結構:
- 抽象聚合角色:定義儲存,添加,洗掉等聚合物件操作,
- 具體聚合角色:實作抽象聚合類,并實作回傳一個迭代器物件的方法,
- 抽象迭代器:定義遍歷和訪問聚合物件的介面,
- 具體迭代器:實作抽象迭代器中的方法,
? 類結構:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-U2sAqBDf-1604422914915)(行為型模式.assets/迭代器模式1.png)]](https://img-blog.csdnimg.cn/20201104010439335.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 代碼實作:
- 抽象聚合角色
//抽象聚合角色
abstract class Aggregate<T> {
protected List<T> list;
public void add(T t) {
list.add(t);
}
abstract Iterator getIterator();
}
- 抽象迭代器
//抽象迭代器
interface Iterator<T> {
boolean hasNext();
T next();
}
- 具體聚合角色
//具體聚合角色
class ConcreteAggregate extends Aggregate {
public ConcreteAggregate() {
list = new ArrayList();
}
@Override
Iterator getIterator() {
return new ConcreteIterator(list);
}
}
- 具體迭代器
//具體迭代器
class ConcreteIterator<T> implements Iterator {
private List<T> list;
private int index = 0;
public ConcreteIterator(List<T> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return list.size() > index;
}
@Override
public T next() {
return list.get(index++);
}
}
- 測驗
Aggregate aggregate = new ConcreteAggregate();
aggregate.add("a");
aggregate.add("b");
aggregate.add("c");
aggregate.add("d");
Iterator iterator = aggregate.getIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//a
//b
//c
//d
? 通常情況下,迭代器模式還可以與組合模式相結合使用,使用迭代器遍歷類似樹結構的資料,類圖如下,代碼不做過多展示,
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iiPxRRJy-1604422914917)(行為型模式.assets/迭代器模式2.png)]](https://img-blog.csdnimg.cn/20201104010503284.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
訪問者模式(Visitor)
? 定義:將作用于某種資料結構種的各元素的操作分離出來封裝成獨立的類,使其在不改變資料結構的前提下可以添加作用于這些元素的新操作,為資料結構種的每個元素提供多種訪問方式,
? 模式結構:
- 抽象訪問者:定義一個訪問具體元素的介面,
- 具體訪問者:實作抽象訪問者,具體每個訪問操作,
- 抽象元素:宣告元素介面,其中包含接收訪問者訪問的方法,
- 具體元素:實作抽象元素中的具體接收訪問方法,
- 物件結構:包含元素角色的容器,
? 類結構:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uvCr5hfI-1604422914918)(行為型模式.assets/訪問者模式.png)]](https://img-blog.csdnimg.cn/20201104010517919.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 代碼實作:
- 抽象元素
//抽象元素
interface Element {
void sayHello();
}
- 具體元素
//具體元素
class ElementA implements Element {
@Override
public void sayHello() {
System.out.println("hi,i am elementA...");
}
}
class ElementB implements Element {
@Override
public void sayHello() {
System.out.println("hi,i am elementB...");
}
}
- 抽象訪問者
//抽象訪問者
interface Visitor {
void visit(Element el);
}
- 具體訪問者
//具體訪問者
class VisitorA implements Visitor {
@Override
public void visit(Element el) {
System.out.print("visitorA Knock knock...");
el.sayHello();
}
}
class VisitorB implements Visitor {
@Override
public void visit(Element el) {
System.out.print("visitorB Knock knock...");
el.sayHello();
}
}
- 結構類
//結構類
class Structure {
private List<Element> elements = new ArrayList<>();
public void add(Element el) {
this.elements.add(el);
}
public void accept(Visitor visitor) {
elements.forEach(el -> visitor.visit(el));
}
}
- 測驗
Structure structure = new Structure();
structure.add(new ElementA());
structure.add(new ElementB());
structure.accept(new VisitorA());
System.out.println("-------------");
structure.accept(new VisitorB());
- 輸出
visitorA Knock knock...hi,i am elementA...
visitorA Knock knock...hi,i am elementB...
-------------
visitorB Knock knock...hi,i am elementA...
visitorB Knock knock...hi,i am elementB...
? 通常情況下,物件結構種有多個具體元素,此時還可以將訪問者模式和組合模式相結合,在遍歷這多個具體元素的時候還可以使用上面的迭代器模式,很是靈活,
備忘錄模式(Memento)
? 定義:在不破壞封裝性的前提下,捕獲一個物件的內部狀態,并在該物件之外保存這個物件,以便以后需要時能將這個物件恢復到之前的狀態,
? 模式結構:
- 發起人角色:記錄當前時刻的內部狀態資訊,提供創建備忘錄和恢復備忘錄的功能,
- 備忘錄角色:儲存發起人的內部狀態,并提供在必要的時候將這些狀態提供給發起人,
- 管理者角色:對備忘錄進行管理,并提供保存和獲取備忘錄的功能,
? 類結構:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-U1tdQSXu-1604422914919)(行為型模式.assets/備忘錄模式.png)]](https://img-blog.csdnimg.cn/20201104010542482.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 代碼實作:
- 備忘錄
//備忘錄
class Memento {
private Stack<String> states = new Stack<>();
public void pushState(String state) {
states.push(state);
}
public String popState() {
return states.peek() != null ? states.pop() : "";
}
}
- 管理者
//管理者
class Caretaker {
private Memento memento;
public void setMemento(Memento m) {
this.memento = m;
}
public Memento getMemento() {
return this.memento;
}
}
- 發起人
//發起人
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return this.state;
}
public Memento createMemento() {
Memento m = new Memento();
m.pushState(this.state);
return m;
}
public void restoreState(Memento m) {
this.state = m.popState();
}
}
- 測驗
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
caretaker.setMemento(originator.createMemento());
System.out.println("------set------");
originator.setState("1");
System.out.println(originator.getState());
caretaker.getMemento().pushState("1");
originator.setState("2");
System.out.println(originator.getState());
caretaker.getMemento().pushState("2");
originator.setState("3");
System.out.println(originator.getState());
caretaker.getMemento().pushState("3");
System.out.println("------restore------");
originator.restoreState(caretaker.getMemento());
System.out.println(originator.getState());
originator.restoreState(caretaker.getMemento());
System.out.println(originator.getState());
originator.restoreState(caretaker.getMemento());
System.out.println(originator.getState());
- 輸出
------set------
1
2
3
------restore------
3
2
1
解釋器模式(Interpreter)
定義:給分析物件一個語言,并定義該語言的文法表示,再設計一個解釋器來決議語言中的句子,
? 剛開始看到解釋器模式的定義的時候,一臉懵逼,編譯器模式常用于對簡單語言的編譯或分析,在介紹編譯器模式之前,首先介紹一下文法,句子,語法樹等概念,
- 文法:描述語言語法結構的形式規則,比如<句子> ::=<主語><謂語><賓語>,<名詞> ::= 大學生|課程|語文,“::=”表示定義為,用“<”,“>”包含的是非終結符,沒有括住的是終結符(這兩個概念后面要用),
- 句子:語言的基本單位,
- 語法樹:句子結構的一種樹形表示,
? 介紹完上面的幾個概念,看一下解釋器模式的幾個主要角色:
- 抽象運算式角色:定義解釋器的介面,約定解釋器的解釋操作,
- 終結符運算式角色:抽象運算式的子類,用來實作文法中與終結符相關的操作,
- 非終結符運算式角色:抽象運算式子類,用來實作文法中與非終結符相關的操作,
- 環境角色:包含解釋器需要的資料或者公共部分,
? 舉例說明:公交車刷卡的時候只有廣州和深圳的老年人和小學生是免費的,其他的都是2元車票錢,刷卡機需要根據輸入的資訊判定是否需要扣錢,那么文法可以定義為:<結果> ::= <城市>的<角色>,根據上面的模式角色,具體的模式類圖如下:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-S1N08aCM-1604422914921)(行為型模式.assets/解釋器模式.png)]](https://img-blog.csdnimg.cn/20201104010605106.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyMjYxMjQ3,size_16,color_FFFFFF,t_70#pic_center)
? 具體代碼設計如下:
- 抽象運算式
//抽象運算式
interface Expression {
boolean interpret(String info);
}
- 終結符運算式
//終結符運算式
class TerminalExpression implements Expression {
private Set<String> set;
public TerminalExpression(String[] data) {
this.set = new HashSet<>(Arrays.asList(data));
}
@Override
public boolean interpret(String info) {
return set.contains(info);
}
}
- 非終結符運算式
//非終結符運算式
class AndExpression implements Expression {
private Expression city;
private Expression person;
public AndExpression(Expression city, Expression person) {
this.city = city;
this.person = person;
}
@Override
public boolean interpret(String info) {
String[] infos = info.split("的");
return city.interpret(infos[0]) && person.interpret(infos[1]);
}
}
- 環境覺得—此處直接使用main方法作為環境
//環境
public static void main(String[] args) {
Expression city = new TerminalExpression(new String[]{"深圳", "廣州"});
Expression person = new TerminalExpression(new String[]{"老年人", "小學生"});
Expression bus = new AndExpression(city, person);
//排隊上車
for (String p : new String[]{"深圳的老人", "廣州的小學生", "深圳的年輕人", "廣州的婦女", "深圳的小學生"}) {
if (bus.interpret(p)) {
System.out.println(p + "乘車免費...");
continue;
}
System.out.println(p + "刷卡2元...");
}
}
- 輸出結果
深圳的老人刷卡2元...
廣州的小學生乘車免費...
深圳的年輕人刷卡2元...
廣州的婦女刷卡2元...
深圳的小學生乘車免費...
END
? 文中涉及的代碼詳見:https://github.com/wupengchoy/helloblog/tree/master/parent/mystudy/src/main/java/com/wupengchoy/mystudy/designpattern
? 至此,經過三周的時間,23種設計模式的概念和大致使用方法都已經大體的學習完成,但這并不意味著結束,在實際應用中,我們不僅僅停留在概念以及一些簡單的例子上,還需要知道每種模式具體在業務中如何使用,以及如何選擇使用何種模式,了解熟悉每種設計模式的優缺點,除此之外,還需要熟悉設計模式中設計的一些法則和演算法,加油,共勉!!
? 學海無涯,苦海作舟,爭取早日掉光頭發,因為光頭……強,
本系列參考人民郵電出版社《軟體設計模式(Java版)》
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/228921.html
標籤:設計模式
上一篇:設計模式—結構型模式
