關注公衆號獲取更多資料
java
行爲型模式描述的死程序運行時複雜的流程控制,描述了多個類或者對象之間怎樣相互協調合做,涉及算法與對象之間的職責分配。git
行爲型模式是23中設計模式中最爲龐大的,包括如下11中:github
@算法
定義:模板方法定義一個操做中的算法骨架,將算法中的一些步驟延遲到子類中去,是的子類能夠在不改變原有算法結構的狀況下從新定義這些算法步驟。設計模式
模板方法模式主要包含一下幾種結構:數據結構
抽象類:定義一個算法的輪廓和骨架多線程
具體子類:繼承了抽象類並實現抽象方法。ide
根據以上角色結構能夠大體畫出以下類圖:學習
舉例說明:五一小長假出去旅遊,須要選擇地點,而後預約計劃,最後選擇出行方式,出行方式但是飛機,火車或者自駕遊等。在這裏選擇地點,定計劃,選擇出行方式能夠理解爲模板方法,選擇出行方式是抽象方法,判斷出行方式爲鉤子方法,定計劃步驟能夠做爲具體方法實現。測試
代碼以下:
//抽象類 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... 預約計劃... 自駕遊...
定義:定義了一系列算法,並將每一個算法封裝起來,使之能夠相互替代,而且算法的改變不會影響到使用者。
策略模式的結構以下:
根據以上結構能夠畫出以下類圖:
模式的實現:
//抽象策略類 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...
對於一個龐大的系統來講,一般狀況下會有不少策略,此時若是直接使用原始的策略模式將會對策略的管理顯得異常困難。將策略模式與工廠模式相結合而成的策略工廠模式將會使得對策略的管理更加方便。升級後的類圖以下,代碼比較簡單,不作過多詳解。
定義:將一個請求封裝成一個對象,使發出的請求的責任和執行請求的責任分割開。
命令模式在平時生活中有不少場景,好比去餐廳吃飯,點餐時點的不一樣的菜品至關於多個請求,隨後這多個不一樣的菜會到廚房分發給不一樣的廚師,此時至關於執行請求的角色,在這個場景中就使得請求和執行分割,咱們點菜的人並不知道廚房具體是如何執行的。
命令模式結構:
類結構以下:
模式實現:
//抽象命令角色 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地址。
定義:爲避免請求發送者與多個請求處理者耦合在一塊兒,將全部的請求處理者經過一個對象記住下一個對象的引用而造成一條鏈式結構;當有請求發生時,請求將沿着這條鏈傳遞,直到有對象處理它爲止。
例如公司請假,請假三天以上和三天之內的審批人不一樣,若是將全部的審批人都依賴於請求者,那麼請求者中都須要依賴全部的審批人對象,若是將請假請求沿着審批人的鏈一個個傳遞下去,直到有人審批或者拒絕,請求中止,此時請求者對象只須要依賴一個審批人對象,從必定程度上下降了耦合。
模式結構:
類結構:
模式實現:
//抽象處理者 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");//請求未處理...
定義:對有狀態的對象,把複雜的判斷邏輯提取到不一樣的對象中,容許對象再起內部狀態發生變化時改變其行爲。
模式結構:
類結構:
舉例說明:多線程在執行過程當中能夠存在多個狀態,能夠簡單的使用狀態模式設計一個多線程的狀態轉換程序,代碼以下:
//抽象狀態 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...
不少狀況下,可能有多個環境享用一組狀態,此時能夠將狀態模式和享元模式結合起來使用,在環境類中儲存共享的狀態。
定義:多個對象之間存在一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於他的對象都會獲得通知並自動更新。
模式結構:
注意:實現觀察者模式時,具體目標和具體觀察者之間不能直接調用,不然二者之間將緊密耦合在一塊兒,違反了面對對象的設計原則。
類結構:
代碼實現:
//抽象觀察者 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(抽象觀察者)定義了觀察者模式,只要實現他們就能夠編寫觀察者模式實例。
定義:定義一箇中介對象來封裝一系列對象之間的交互,使原有對象之間的耦合鬆散,而且能夠獨立的改變他們之間的交互。
模式結構:
類結構:
代碼實現:
//抽象中介者 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
定義:提供一個對象來順序訪問聚合對象中的一系列數據,二部暴露聚合對象的內部表示。
模式結構:
類結構:
代碼實現:
//抽象聚合角色 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
一般狀況下,迭代器模式還能夠與組合模式相結合使用,使用迭代器遍歷相似樹結構的數據,類圖以下,代碼不作過多展現。
定義:將做用於某種數據結構種的各元素的操做分離出來封裝成獨立的類,使其在不改變數據結構的前提下能夠添加做用於這些元素的新操做,爲數據結構種的每一個元素提供多種訪問方式。
模式結構:
類結構:
代碼實現:
//抽象元素 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...
一般狀況下,對象結構種有多個具體元素,此時還能夠將訪問者模式和組合模式相結合,在遍歷這多個具體元素的時候還可使用上面的迭代器模式,非常靈活。
定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個對象,以便之後須要時能將這個對象恢復到以前的狀態。
模式結構:
類結構:
代碼實現:
//備忘錄 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
定義:給分析對象一個語言,並定義該語言的文法表示,再設計一個解釋器來解析語言中的句子。
剛開始看到解釋器模式的定義的時候,一臉懵逼。編譯器模式經常使用於對簡單語言的編譯或分析。在介紹編譯器模式以前,首先介紹一下文法,句子,語法樹等概念。
- 文法:描述語言語法結構的形式規則。好比<句子> ::=<主語><謂語><賓語>,<名詞> ::= 大學生|課程|語文。「::=」表示定義爲。用「<」,「>」包含的是非終結符,沒有括住的是終結符(這兩個概念後面要用)。
- 句子:語言的基本單位。
- 語法樹:句子結構的一種樹形表示。
介紹完上面的幾個概念,看一下解釋器模式的幾個主要角色:
舉例說明:公交車刷卡的時候只有廣州和深圳的老年人和小學生是免費的,其餘的都是2元車票錢,刷卡機須要根據輸入的信息斷定是否須要扣錢,那麼文法能夠定義爲:<結果> ::= <城市>的<角色>。根據上面的模式角色,具體的模式類圖以下:
具體代碼設計以下:
//抽象表達式 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]); } }
//環境 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
至此,通過三週的時間,23種設計模式的概念和大體使用方法都已經大致的學習完成,但這並不意味着結束。在實際應用中,咱們不只僅停留在概念以及一些簡單的例子上,還須要知道每種模式具體在業務中如何使用,以及如何選擇使用何種模式。瞭解熟悉每種設計模式的優缺點,除此以外,還須要熟悉設計模式中設計的一些法則和算法。加油,共勉!!
學海無涯,苦海做舟。爭取早日掉光頭髮,由於光頭……強。
本系列參考人民郵電出版社《軟件設計模式(Java版)》