前兩篇博客分別介紹了設計模式中的建造型模式和結構型模式,此次就來說講行爲型模式。建造型模式和結構型模式分別規範了對象的構造與對象間的組合,而行爲型模式的意義在於提供了對象間的通訊方式。下面來看幾種常見的行爲型模式。java
責任鏈模型,目的是使請求發送者與接受者解耦,通俗的說,就是將多個可能的請求接受者放在一條鏈表上(責任鏈),而發送者徹底不關心接受者的內部實現,甚至不關心究竟是哪一個對象響應了本身的請求,它只須要將本身的請求拋出,或者說發送請求到責任鏈上,責任鏈上的一系列對象便會判斷是否對請求進行處理。這個模式適用於對同一請求可能會有多個對象進行處理的狀況,具體使用哪一個對象在運行時判斷。下面看一份源碼,實現了三種類型的日誌記錄器,經過判斷請求級別是否相同來決定是否進行記錄。數據庫
public abstract class AbstractLogger { public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3; protected int level; protected AbstractLogger nextLogger; public void setNextLogger(AbstractLogger nextLogger){ this.nextLogger = nextLogger; } public void logMessage(int level, String message){ if(this.level == level){ write(message); } if(nextLogger !=null){ nextLogger.logMessage(level, message); } } abstract protected void write(String message); }
public class ConsoleLogger extends AbstractLogger { public ConsoleLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("Standard Console::Logger: " + message); } } public class ErrorLogger extends AbstractLogger { public ErrorLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("Error Console::Logger: " + message); } } public class FileLogger extends AbstractLogger { public FileLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("File::Logger: " + message); } }
經過以上的數據結構即可以將三種日誌記錄器設置在一條鏈表上,對第一個結點使用 logMessage 函數就是把請求發送到責任鏈上,每一個接受對象判斷是否進行處理。編程
命令模式是另外一種讓行爲請求者和行爲實現者解耦的方式,實現方式是將請求以命令的形式包裹在對象中,並傳給調用對象。命令模式的核心在於實現三個角色:命令真正執行者、命令、調用者,將這三者分別實現後大大下降了行爲請求與實現的耦合度,且能夠很方便地添加新命令。例如要實現股票的買賣請求:設計模式
public interface Order { void execute(); }
public class Stock { private String name = "ABC"; private int quantity = 10; public void buy(){ System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] bought"); } public void sell(){ System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] sold"); } }
public class BuyStock implements Order { private Stock abcStock; public BuyStock(Stock abcStock){ this.abcStock = abcStock; } public void execute() { abcStock.buy(); } }
public class SellStock implements Order { private Stock abcStock; public SellStock(Stock abcStock){ this.abcStock = abcStock; } public void execute() { abcStock.sell(); } }
public class Broker { private List<Order> orderList = new ArrayList<Order>(); public void takeOrder(Order order){ orderList.add(order); } public void placeOrders(){ for (Order order : orderList) { order.execute(); } orderList.clear(); } }
public class CommandPatternDemo { public static void main(String[] args) { Stock abcStock = new Stock(); BuyStock buyStockOrder = new BuyStock(abcStock); SellStock sellStockOrder = new SellStock(abcStock); Broker broker = new Broker(); broker.takeOrder(buyStockOrder); broker.takeOrder(sellStockOrder); broker.placeOrders(); } }
上述代碼中, Stock 類是命名的真正執行者,而 BuyStock 類和 SellStock 類分別實現了 Order 接口,承擔了命令的角色, Broker 類是命令調用者,客戶須要執行什麼操做,只需將命令對象添加到調用者對象並讓其執行便可。數據結構
接着看看迭代器模式,即遍歷一個聚合對象的方式,Java中的每一個集合類都有很是成熟的迭代器來進行遍歷操做,這裏就給出自定義對象的迭代器模式。ide
public interface Iterator { public boolean hasNext(); public Object next(); }
public interface Container { public Iterator getIterator(); }
public class NameRepository implements Container { public String names[] = {"Robert" , "John" ,"Julie" , "Lora"}; @Override public Iterator getIterator() { return new NameIterator(); } private class NameIterator implements Iterator { int index; @Override public boolean hasNext() { if(index < names.length){ return true; } return false; } @Override public Object next() { if(this.hasNext()){ return names[index++]; } return null; } } }
這裏用到了 java 中 private 內部類,僅在所屬外部類中可見。一個迭代器類須要實現 hasNext 函數判斷是否還有下一元素,以及 next 函數返回下一元素,而使用迭代器的集合類須要實現 getIterator 函數獲得該集合的迭代器。這樣一個迭代器模式就完成了。函數
再來看備忘錄模式,其保存一個對象當前的狀態以便之後恢復對象,就像遊戲中的恢復存檔以及數據庫的事務管理等,給用戶提供了一種能夠恢復狀態的機制。一種好的備忘錄模式須要實現信息封裝,使得用戶不須要關心狀態的保存細節。Java中可創建三個類來實現備忘錄模式:狀態類(保存狀態信息)、狀態建立類(用於建立一個狀態)、狀態保存類(創建一個集合保存過往的狀態)。示例代碼以下:this
public class Memento { private String state; public Memento(String state){ this.state = state; } public String getState(){ return state; } }
public class Originator { private String state; public void setState(String state){ this.state = state; } public String getState(){ return state; } public Memento saveStateToMemento(){ return new Memento(state); } public void getStateFromMemento(Memento Memento){ state = Memento.getState(); } }
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); } }
以上即是三種類的定義,須要保存狀態時調用 Originator 類的 saveStateToMemento 函數並 add 到 CareTaker 對象的 ArrayList 中。spa
接着看看模板模式,一種常常出現的設計模式,不少常用它的人甚至不以爲這算是一種「高大上」的設計模式。模板模式使用一個抽象類(模板)定義了執行它的方法的方式,它的子類能夠按須要重寫方法實現,說白了,就是規範了抽象類該怎麼使用。其優勢是可在不變部分的基礎上進行擴展 ,且提取了公共代碼,便於維護。示例代碼:設計
public abstract class Game { abstract void initialize(); abstract void startPlay(); abstract void endPlay(); public final void play(){ initialize(); startPlay(); endPlay(); } }
public class Football extends Game { @Override void endPlay() { System.out.println("Football Game Finished!"); } @Override void initialize() { System.out.println("Football Game Initialized! Start playing."); } @Override void startPlay() { System.out.println("Football Game Started. Enjoy the game!"); } }
這裏要強調的是模板類 play 函數前的 final 修飾符,該修飾符的含義是此函數不能被重寫,保證了抽象類中不變的部分不可改變,防止子類惡意修改,這也是定義模板時的重要原則,即公共不可變部分用 final 修飾。這一點在我之前的編程經驗中是從未想到過的,可見該設計模式具備很重要的意義。
下面說說界面編程中常常出現的觀察者模式,該模式描述的是對象間的一對多關係,即當一個對象被修改時,則會自動通知它的依賴對象。這一模式在GUI編程中常常出現,好比Qt的信號槽機制,Android中的Rxjava庫。該模式提供的是通常性觸發機制的方案。下面給出被觀察者的源碼(「一對多」關係中的「一」):
public class Subject { private List<Observer> observers = new ArrayList<Observer>(); private int state; public int getState() { return state; } public void setState(int state) { this.state = state; notifyAllObservers(); } public void attach(Observer observer){ observers.add(observer); } public void notifyAllObservers(){ for (Observer observer : observers) { observer.update(); } } }
給出了 attach 函數和 notifyAllObservers 函數後,觀察者模式的原理就一目瞭然了,剩下的工做就是對不一樣的觀察者實現 update 函數。
最後再看一種經典的設計模式:MVC模式,即Model-View-Controller(模型-視圖-控制器) 模式。這種模式常常在各個場合被提起,其意義在於很好地實現了應用程序各模塊之間的解耦。Model表明存取數據的對象,View表示數據可視化對象,Controller負責Model和View之間的交互,使得數據與顯示之間徹底分離,這對於應用程序開發具備很大的意義。因爲該模式十分常見,在此不給出示例源碼。
其餘行爲型模式好比空對象模式、狀態模式、中介者模式等留到之後有機會再分析。總結一下行爲型設計模式的核心思想:經過封裝和解耦來實現對象間通訊需求。