設計模式:(四)行為型模式

行為型模式.png
一、策略模式

策略模式.png

策略模式通用類圖.png
策略模式使用的就是面向物件的繼承和多型機制,非常容易理解和掌握,策略模式的三個角色:
-
Context封裝角色
它也叫做上下文角色,起承上啟下封裝作用,遮蔽高層模組對策略、演算法的直接訪問,封裝可能存在的變化。
-
Strategy抽象策略角色
策略、演算法家族的抽象,通常為介面,定義每個策略或演算法必須具有的方法和屬性。,類圖中的AlgorithmInterface是什麼意思,algorithm是“運演算法則”的意思,結合起來意思就明白了。
-
ConcreteStrategy具體策略角色
實現抽象策略中的操作,該類含有具體的演算法。
//抽象的策略角色 public interface Strategy { //策略模式的運演算法則 public void doSomething(); } //具體策略也是非常普通的一個實現類,只要實現介面中的方法就可以 public class ConcreteStrategy1 implements Strategy { public void doSomething() { System.out.println("具體策略1的運演算法則"); } } public class ConcreteStrategy2 implements Strategy { public void doSomething() { System.out.println("具體策略2的運演算法則"); } } //封裝角色 public class Context { //抽象策略 private Strategy strategy = null; //建構函式設定具體策略 public Context(Strategy _strategy){ this.strategy = _strategy; } //封裝後的策略方法 public void doAnythinig(){ this.strategy.doSomething(); } } //高層模組 public class Client { public static void main(String[] args) { //宣告一個具體的策略 Strategy strategy = new ConcreteStrategy1(); //宣告上下文物件 Context context = new Context(strategy); //執行封裝後的方法 context.doAnythinig(); } }
策略模式的重點就是封裝角色,它是借用了代理模式的思路,大家可以想想,它和代理模式有什麼差別,差別就是策略模式的封裝角色和被封裝的策略類不用是同一個介面,如果是同一個介面那就成為了代理模式。
二、模板方法模式

模板方法模式.png

模板方法模式.png
模板方法模式確實非常簡單,僅僅使用了Java的繼承機制,但它是一個應用非常廣泛的模式。其中,AbstractClass叫做抽象模板,它的方法分為兩類:
-
基本方法
基本方法也叫做基本操作,是由子類實現的方法,並且在模板方法被呼叫。
-
模板方法
可以有一個或幾個,一般是一個具體方法,也就是一個框架,實現對基本方法的排程,完成固定的邏輯。
為了防止惡意的操作,一般模板方法都加上final關鍵字,不允許被覆寫。
在類圖中還有一個角色:具體模板。ConcreteClass1和ConcreteClass2屬於具體模板,實現父類所定義的一個或多個抽象方法,也就是父類定義的基本方法在子類中得以實現。
//抽象模板類 public abstract class AbstractClass { //基本方法 protected abstract void doSomething(); //基本方法 protected abstract void doAnything(); //模板方法 public void templateMethod(){ /* * 呼叫基本方法,完成相關的邏輯 */ this.doAnything(); this.doSomething(); } } // 具體模板類 public class ConcreteClass1 extends AbstractClass { //實現基本方法 protected void doAnything() { //業務邏輯處理 } protected void doSomething() { //業務邏輯處理 } } public class ConcreteClass2 extends AbstractClass { //實現基本方法 protected void doAnything() { //業務邏輯處理 } protected void doSomething() { //業務邏輯處理 } } //場景類 public class Client { public static void main(String[] args) { AbstractClass class1 = new ConcreteClass1(); AbstractClass class2 = new ConcreteClass2(); //呼叫模板方法 class1.templateMethod(); class2.templateMethod(); } }
抽象模板中的基本方法儘量設計為protected型別,符合迪米特法則,不需要暴露的屬性或方法儘量不要設定為protected型別。實現類若非必要,儘量不要擴大父類中的訪問許可權。
三、觀察者模式

觀察者模式.png

觀察者模式通用類圖
-
Subject被觀察者
定義被觀察者必須實現的職責,它必須能夠動態地增加、取消觀察者。它一般是抽象類或者是實現類,僅僅完成作為被觀察者必須實現的職責:管理觀察者並通知觀察者。
-
Observer觀察者
觀察者接收到訊息後,即進行update(更新方法)操作,對接收到的資訊進行處理。
-
ConcreteSubject具體的被觀察者
定義被觀察者自己的業務邏輯,同時定義對哪些事件進行通知。
-
ConcreteObserver具體的觀察者
每個觀察在接收到訊息後的處理反應是不同,各個觀察者有自己的處理邏輯。
// 被觀察者 public abstract class Subject { //定義一個觀察者陣列 private Vector<Observer> obsVector = new Vector<Observer>(); //增加一個觀察者 public void addObserver(Observer o){ this.obsVector.add(o); } //刪除一個觀察者 public void delObserver(Observer o){ this.obsVector.remove(o); } //通知所有觀察者 public void notifyObservers(){ for(Observer o:this.obsVector){ o.update(); } } } //具體被觀察者 public class ConcreteSubject extends Subject { //具體的業務 public void doSomething(){ /* * do something */ super.notifyObservers(); } } //觀察者 public interface Observer { //更新方法 public void update(); } //具體觀察者 public class ConcreteObserver implements Observer { //實現更新方法 public void update() { System.out.println("接收到資訊,並進行處理!"); } } //場景類 public class Client { public static void main(String[] args) { //建立一個被觀察者 ConcreteSubject subject = new ConcreteSubject(); //定義一個觀察者 Observer obs= new ConcreteObserver(); //觀察者觀察被觀察者 subject.addObserver(obs); //觀察者開始活動了 subject.doSomething(); } }
被觀察者的職責非常簡單,就是定義誰能夠觀察,誰不能觀察,程式中使用ArrayList和Vector沒有太大的差別,ArrayList是執行緒非同步,不安全;Vector是執行緒同步,安全——就這點區別。
四、迭代模式

迭代模式.png
迭代器是為容器服務的,那什麼是容器呢? 能容納物件的所有型別都可以稱之為容器,例如Collection集合型別、Set型別等,迭代器模式就是為解決遍歷這些容器中的元素而誕生的

迭代器模式通用類圖.png
-
Iterator抽象迭代器
抽象迭代器負責定義訪問和遍歷元素的介面,而且基本上是有固定的3個方法:first()獲得第一個元素,next()訪問下一個元素,isDone()是否已經訪問到底部(Java叫做hasNext()方法)。
-
ConcreteIterator具體迭代器
具體迭代器角色要實現迭代器介面,完成容器元素的遍歷。
-
Aggregate抽象容器
容器角色負責提供建立具體迭代器角色的介面,必然提供一個類似createIterator()這樣的方法,在Java中一般是iterator()方法。
-
Concrete Aggregate具體容器
具體容器實現容器介面定義的方法,創建出容納迭代器的物件。
//抽象迭代器 public interface Iterator { //遍歷到下一個元素 public Object next(); //是否已經遍歷到尾部 public boolean hasNext(); //刪除當前指向的元素 public boolean remove(); } //具體迭代器 public class ConcreteIterator implements Iterator { private Vector vector = new Vector(); //定義當前遊標 public int cursor = 0; @SuppressWarnings("unchecked") public ConcreteIterator(Vector _vector){ this.vector = _vector; } //判斷是否到達尾部 public boolean hasNext() { if(this.cursor == this.vector.size()){ return false; }else{ return true; } } //返回下一個元素 public Object next() { Object result = null; if(this.hasNext()){ result = this.vector.get(this.cursor++); }else{ result = null; } return result; } //刪除當前元素 public boolean remove() { this.vector.remove(this.cursor); return true; } } //抽象容器 public interface Aggregate { //是容器必然有元素的增加 public void add(Object object); //減少元素 public void remove(Object object); //由迭代器來遍歷所有的元素 public Iterator iterator(); } //具體容器 public class ConcreteAggregate implements Aggregate { //容納物件的容器 private Vector vector = new Vector(); //增加一個元素 public void add(Object object) { this.vector.add(object); } //返回迭代器物件 public Iterator iterator() { return new ConcreteIterator(this.vector); } //刪除一個元素 public void remove(Object object) { this.remove(object); } } //場景類 public class Client { public static void main(String[] args) { //宣告出容器 Aggregate agg = new ConcreteAggregate(); //產生物件資料放進去 agg.add("abc"); agg.add("aaa"); agg.add("1234"); //遍歷一下 Iterator iterator = agg.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } } }
五、責任鏈模式

責任鏈模式.png
責任鏈模式的重點是在“鏈”上,由一條鏈去處理相似的請求在鏈中決定誰來處理這個請求,並返回相應的結果。

責任鏈模式通用類圖.png
//抽象處理者 public abstract class Handler { private Handler nextHandler; //每個處理者都必須對請求做出處理 public final Response handleMessage(Request request){ Response response = null; //判斷是否是自己的處理級別 if(this.getHandlerLevel().equals(request.getRequestLevel())){ response = this.echo(request); }else{//不屬於自己的處理級別 //判斷是否有下一個處理者 if(this.nextHandler != null){ response = this.nextHandler.handleMessage(request); }else{ //沒有適當的處理者,業務自行處理 } } return response; } //設定下一個處理者是誰 public void setNext(Handler handler){ this.nextHandler = handler; } //每個處理者都有一個處理級別 protected abstract Level getHandlerLevel(); //每個處理者都必須實現處理任務 protected abstract Response echo(Request request); } //具體處理者 public class ConcreteHandler1 extends Handler { //定義自己的處理邏輯 protected Response echo(Request request) { //完成處理邏輯 return null; } //設定自己的處理級別 protected Level getHandlerLevel() { //設定自己的處理級別 return null; } } public class ConcreteHandler2 extends Handler { //定義自己的處理邏輯 protected Response echo(Request request) { //完成處理邏輯 return null; } //設定自己的處理級別 protected Level getHandlerLevel() { //設定自己的處理級別 return null; } } public class ConcreteHandler3 extends Handler { //定義自己的處理邏輯 protected Response echo(Request request) { //完成處理邏輯 return null; } //設定自己的處理級別 protected Level getHandlerLevel() { //設定自己的處理級別 return null; } } //場景類 public class Client { public static void main(String[] args) { //宣告所有的處理節點 Handler handler1 = new ConcreteHandler1(); Handler handler2 = new ConcreteHandler2(); Handler handler3 = new ConcreteHandler3(); //設定鏈中的階段順序1-->2-->3 handler1.setNext(handler2); handler2.setNext(handler3); //提交請求,返回結果 Response response = handler1.handlerMessage(new Request()); } }
六、命令模式

命令模式.png

命令模式通用類圖.png
- Receiver接收者角色
該角色就是幹活的角色,命令傳遞到這裡是應該被執行的。 - Command命令角色
需要執行的所有命令都在這裡宣告。 - Invoker呼叫者角色
接收到命令,並執行命令
//通用Receiver類 public abstract class Receiver { //抽象接收者,定義每個接收者都必須完成的業務 public abstract void doSomething(); } //具體的Receiver類 public class ConcreteReciver1 extends Receiver{ //每個接收者都必須處理一定的業務邏輯 public void doSomething(){ } } public class ConcreteReciver2 extends Receiver{ //每個接收者都必須處理一定的業務邏輯 public void doSomething(){ } } //抽象的Command類 public abstract class Command { //每個命令類都必須有一個執行命令的方法 public abstract void execute(); } //具體的Command類 public class ConcreteCommand1 extends Command { //對哪個Receiver類進行命令處理 private Receiver receiver; //建構函式傳遞接收者 public ConcreteCommand1(Receiver receiver){ this.receiver = receiver; } //必須實現一個命令 public void execute() { //業務處理 this.receiver.doSomething(); } } public class ConcreteCommand2 extends Command { //哪個Receiver類進行命令處理 private Receiver receiver; //建構函式傳遞接收者 public ConcreteCommand2(Receiver receiver){ this.receiver = receiver; } //必須實現一個命令 public void execute() { //業務處理 this.receiver.doSomething(); } } //呼叫者Invoker類 public class Invoker { private Command command; //受氣包,接受命令 public void setCommand(Command command){ this.command = command; } //執行命令 public void action(){ this.command.execute(); } } //場景類 public class Client { public static void main(String[] args) { //首先宣告呼叫者Invoker Invoker invoker = new Invoker(); //定義接收者 Receiver receiver = new ConcreteReciver1(); //定義一個傳送給接收者的命令 Command command = new ConcreteCommand1(receiver); //把命令交給呼叫者去執行 invoker.setCommand(command); invoker.action(); } }
七、備忘錄模式

備忘錄模式.png

備忘錄模式通用類圖.png
- Originator發起人角色
記錄當前時刻的內部狀態,負責定義哪些屬於備份範圍的狀態,負責建立和恢復備忘錄資料。 - Memento備忘錄角色
負責儲存Originator發起人物件的內部狀態,在需要的時候提供發起人需要的內部狀態。 - Caretaker備忘錄管理員角色
對備忘錄進行管理、儲存和提供備忘錄。
//發起人角色 public class Originator { //內部狀態 private String state = ""; public String getState() { return state; } public void setState(String state) { this.state = state; } //建立一個備忘錄 public Memento createMemento(){ return new Memento(this.state); } //恢復一個備忘錄 public void restoreMemento(Memento _memento){ this.setState(_memento.getState()); } } //備忘錄角色 public class Memento { //發起人的內部狀態 private String state = ""; //建構函式傳遞引數 public Memento(String _state){ this.state = _state; } public String getState() { return state; } public void setState(String state) { this.state = state; } } //備忘錄管理員角色 public class CareTaker { private List<Memento> mementoList = new ArrayList<Memento>(); public void add(Memento state){ mementoList.add(state); } public Memento get(int index){ return mementoList.get(index); } } //場景類 public class Client { public static void main(String[] args) { Originator originator = new Originator(); CareTaker careTaker = new CareTaker(); originator.setState("State #1"); originator.setState("State #2"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #3"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #4"); System.out.println("Current State: " + originator.getState()); originator.restoreMemento(careTaker.get(0)); System.out.println("First saved State: " + originator.getState()); originator.restoreMemento(careTaker.get(1)); System.out.println("Second saved State: " + originator.getState()); } }
八、狀態模式

狀態模式.png

狀態模式通用類圖.png
- State——抽象狀態角色
介面或抽象類,負責物件狀態定義,並且封裝環境角色以實現狀態切換。 - ConcreteState——具體狀態角色
每一個具體狀態必須完成兩個職責:本狀態的行為管理以及趨向狀態處理,通俗地說,就是本狀態下要做的事情,以及本狀態如何過渡到其他狀態。 - Context——環境角色
定義客戶端需要的介面,並且負責具體狀態的切換。
//抽象狀態角色 public abstract class State { //定義一個環境角色,提供子類訪問 protected Context context; //設定環境角色 public void setContext(Context _context){ this.context = _context; } //行為1 public abstract void handle1(); //行為2 public abstract void handle2(); } //狀態角色 public class ConcreteState1 extends State { @Override public void handle1() { //本狀態下必須處理的邏輯 } @Override public void handle2() { //設定當前狀態為stat2 super.context.setCurrentState(Context.STATE2); //過渡到state2狀態,由Context實現 super.context.handle2(); } } public class ConcreteState2 extends State { @Override public void handle1() { //設定當前狀態為state1 super.context.setCurrentState(Context.STATE1); //過渡到state1狀態,由Context實現 super.context.handle1(); } @Override public void handle2() { //本狀態下必須處理的邏輯 } } //具體環境角色 public class Context { //定義狀態 public final static State STATE1 = new ConcreteState1(); public final static State STATE2 = new ConcreteState2(); //當前狀態 private State CurrentState; //獲得當前狀態 public State getCurrentState() { return CurrentState; } //設定當前狀態 public void setCurrentState(State currentState) { this.CurrentState = currentState; //切換狀態 this.CurrentState.setContext(this); } //行為委託 public void handle1(){ this.CurrentState.handle1(); } public void handle2(){ this.CurrentState.handle2(); } }
環境角色有兩個不成文的約束:
- 把狀態物件宣告為靜態常量,有幾個狀態物件就宣告幾個靜態常量。
- 環境角色具有狀態抽象角色定義的所有行為,具體執行使用委託方式。
九、訪問者模式

訪問者模式.png

訪問者模式通用類圖.png
- Visitor——抽象訪問者
抽象類或者介面,宣告訪問者可以訪問哪些元素,具體到程式中就是visit方法的引數定義哪些物件是可以被訪問的。 - ConcreteVisitor——具體訪問者
它影響訪問者訪問到一個類後該怎麼幹,要做什麼事情。 - Element——抽象元素
介面或者抽象類,宣告接受哪一類訪問者訪問,程式上是通過accept方法中的引數來定義的。 - ConcreteElement——具體元素
實現accept方法,通常是visitor.visit(this),基本上都形成了一種模式了。 - ObjectStruture——結構物件
“元素產生者,一般容納在多個不同類、不同介面的容器,如List、Set、Map等,在專案中,一般很少抽象出這個角色。
//抽象元素 public abstract class Element { //定義業務邏輯 public abstract void doSomething(); //允許誰來訪問 public abstract void accept(IVisitor visitor); } //具體元素 public class ConcreteElement1 extends Element{ //完善業務邏輯 public void doSomething(){ //業務處理 } //允許那個訪問者訪問 public void accept(IVisitor visitor){ visitor.visit(this); } } public class ConcreteElement2 extends Element{ //完善業務邏輯 public void doSomething(){ //業務處理 } //允許那個訪問者訪問 public void accept(IVisitor visitor){ visitor.visit(this); } } //抽象訪問者 public interface IVisitor { //可以訪問哪些物件 public void visit(ConcreteElement1 el1); public void visit(ConcreteElement2 el2); } //具體訪問者 public class Visitor implements IVisitor { //訪問el1元素 public void visit(ConcreteElement1 el1) { el1.doSomething(); } //訪問el2元素 public void visit(ConcreteElement2 el2) { el2.doSomething(); } } // 結構物件 public class ObjectStruture { //物件生成器,這裡通過一個工廠方法模式模擬 public static Element createElement(){ Random rand = new Random(); if(rand.nextInt(100) > 50){ return new ConcreteElement1(); }else{ return new ConcreteElement2(); } } } // 場景類 public class Client { public static void main(String[] args) { for(int i=0;i<10;i++){ //獲得元素物件 Element el = ObjectStruture.createElement(); //接受訪問者訪問 el.accept(new Visitor()); } } }
十、中介者模式

中介者模式.png

中介者模式通用類圖.png
- Mediator 抽象中介者角色
抽象中介者角色定義統一的介面,用於各同事角色之間的通訊。 - Concrete Mediator 具體中介者角色
具體中介者角色通過協調各同事角色實現協作行為,因此它必須依賴於各個同事角色。 - Colleague 同事角色
每一個同事角色都知道中介者角色,而且與其他的同事角色通訊的時候,一定要通過中介者角色協作
//通用抽象中介者 public abstract class Mediator { //定義同事類 protected ConcreteColleague1 c1; protected ConcreteColleague2 c2; //通過getter/setter方法把同事類注入進來 public ConcreteColleague1 getC1() { return c1; } public void setC1(ConcreteColleague1 c1) { this.c1 = c1; } public ConcreteColleague2 getC2() { return c2; } public void setC2(ConcreteColleague2 c2) { this.c2 = c2; } //中介者模式的業務邏輯 public abstract void doSomething1(); public abstract void doSomething2(); } // 通用中介者 public class ConcreteMediator extends Mediator { @Override public void doSomething1() { //呼叫同事類的方法,只要是public方法都可以呼叫 super.c1.selfMethod1(); super.c2.selfMethod2(); } public void doSomething2() { super.c1.selfMethod1(); super.c2.selfMethod2(); } } // 抽象同事類 public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator _mediator){ this.mediator = _mediator; } } // 具體同事類 public class ConcreteColleague1 extends Colleague { //通過建構函式傳遞中介者 public ConcreteColleague1(Mediator _mediator){ super(_mediator); } //自有方法 self-method public void selfMethod1(){ //處理自己的業務邏輯 } //依賴方法 dep-method public void depMethod1(){ //處理自己的業務邏輯 //自己不能處理的業務邏輯,委託給中介者處理 super.mediator.doSomething1(); } } public class ConcreteColleague2 extends Colleague { //通過建構函式傳遞中介者 public ConcreteColleague2(Mediator _mediator){ super(_mediator); } //自有方法 self-method public void selfMethod2(){ //處理自己的業務邏輯 } //依賴方法 dep-method public void depMethod2“(){ //處理自己的業務邏輯 //自己不能處理的業務邏輯,委託給中介者處理 super.mediator.doSomething2(); } }
十一、直譯器模式

直譯器模式.png

直譯器模式通用類圖.png
- TerminalExpression——終結符表示式
實現與文法中的元素相關聯的解釋操作,通常一個直譯器模式中只有一個終結符表示式,但有多個例項,對應不同的終結符。具體到我們例子就是VarExpression類,表示式中的每個終結符都在棧中產生了一個VarExpression物件。 - NonterminalExpression——非終結符表示式
文法中的每條規則對應於一個非終結表示式,具體到我們的例子就是加減法規則分別對應到AddExpression和SubExpression兩個類。非終結符表示式根據邏輯的複雜程度而增加,原則上每個文法規則都對應一個非終結符表示式。 - Context——環境角色
//抽象表示式 public abstract class Expression { //每個表示式必須有一個解析任務 public abstract Object interpreter(Contextctx); } //終結符表示式 public class TerminalExpression extends Expression { //通常終結符表示式只有一個,但是有多個物件 public Object interpreter(Context ctx) { return null; } } // 非終結符表示式 public class NonterminalExpression extends Expression { //每個非終結符表示式都會對其他表示式產生依賴 public NonterminalExpression(Expression... expression){ } public Object interpreter(Context ctx) { //進行文法處理 return null; } } //客戶類 public class Client { public static void main(String[] args) { Context ctx = new Context(); //通常定一個語法容器,容納一個具體的表示式,通常為ListArray、LinkedList、Stack等型別 Stack&Expression> stack = null; for(;;){ //進行語法判斷,併產生遞迴呼叫 } //產生一個完整的語法樹,由各個具體的語法分析進行解析 Expression exp = stack.pop(); //具體元素進入場景 exp.interpreter(ctx); } }