設計模式讀書筆記3

前兩篇博客分別介紹了設計模式中的建造型模式和結構型模式,此次就來說講行爲型模式。建造型模式和結構型模式分別規範了對象的構造與對象間的組合,而行爲型模式的意義在於提供了對象間的通訊方式。下面來看幾種常見的行爲型模式。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之間的交互,使得數據與顯示之間徹底分離,這對於應用程序開發具備很大的意義。因爲該模式十分常見,在此不給出示例源碼。

 

其餘行爲型模式好比空對象模式、狀態模式、中介者模式等留到之後有機會再分析。總結一下行爲型設計模式的核心思想:經過封裝和解耦來實現對象間通訊需求。

相關文章
相關標籤/搜索