java設計模式-可複用面向對象軟件的基礎(三)

本章是關於設計模式的最後一講,會講到第三種設計模式——行爲型模式,共11種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。這段時間一直在寫關於設計模式的東西,終於寫到一半了,寫博文是個很費時間的東西,由於我得爲讀者負責,不管是圖仍是代碼仍是表述,都但願能儘可能寫清楚,以便讀者理解,我想不管是我仍是讀者,都但願看到高質量的博文出來,從我本人出發,我會一直堅持下去,不斷更新,源源動力來自於讀者朋友們的不斷支持,我會盡本身的努力,寫好每一篇文章!但願你們能不斷給出意見和建議,共同打造完美的博文!java

 

 先來張圖,看看這11中模式的關係:算法

第一類:經過父類與子類的關係進行實現。第二類:兩個類之間。第三類:類的狀態。第四類:經過中間類小程序

1三、策略模式(strategy)設計模式

策略模式定義了一系列算法,並將每一個算法封裝起來,使他們能夠相互替換,且算法的變化不會影響到使用算法的客戶。須要設計一個接口,爲一系列實現類提供統一的方法,多個實現類實現該接口,設計一個抽象類(無關緊要,屬於輔助類),提供輔助函數,關係圖以下:框架

圖中ICalculator提供贊成的方法,
AbstractCalculator是輔助類,提供輔助方法,接下來,依次實現下每一個類:ide

首先統一接口:函數

[java] view plaincopy 測試

  1. public interface ICalculator {  優化

  2.     public int calculate(String exp);  this

  3. }  

輔助類:

[java] view plaincopy

  1. public abstract class AbstractCalculator {  

  2.       

  3.     public int[] split(String exp,String opt){  

  4.         String array[] = exp.split(opt);  

  5.         int arrayInt[] = new int[2];  

  6.         arrayInt[0] = Integer.parseInt(array[0]);  

  7.         arrayInt[1] = Integer.parseInt(array[1]);  

  8.         return arrayInt;  

  9.     }  

  10. }  

三個實現類:

[java] view plaincopy

  1. public class Plus extends AbstractCalculator implements ICalculator {  

  2.   

  3.     @Override  

  4.     public int calculate(String exp) {  

  5.         int arrayInt[] = split(exp,"\\+");  

  6.         return arrayInt[0]+arrayInt[1];  

  7.     }  

  8. }  

[java] view plaincopy

  1. public class Minus extends AbstractCalculator implements ICalculator {  

  2.   

  3.     @Override  

  4.     public int calculate(String exp) {  

  5.         int arrayInt[] = split(exp,"-");  

  6.         return arrayInt[0]-arrayInt[1];  

  7.     }  

  8.   

  9. }  

[java] view plaincopy

  1. public class Multiply extends AbstractCalculator implements ICalculator {  

  2.   

  3.     @Override  

  4.     public int calculate(String exp) {  

  5.         int arrayInt[] = split(exp,"\\*");  

  6.         return arrayInt[0]*arrayInt[1];  

  7.     }  

  8. }  

簡單的測試類:

[java] view plaincopy

  1. public class StrategyTest {  

  2.   

  3.     public static void main(String[] args) {  

  4.         String exp = "2+8";  

  5.         ICalculator cal = new Plus();  

  6.         int result = cal.calculate(exp);  

  7.         System.out.println(result);  

  8.     }  

  9. }  

輸出:10

策略模式的決定權在用戶,系統自己提供不一樣算法的實現,新增或者刪除算法,對各類算法作封裝。所以,策略模式多用在算法決策系統中,外部用戶只須要決定用哪一個算法便可。


1四、模板方法模式(Template Method)

解釋一下模板方法模式,就是指:一個抽象類中,有一個主方法,再定義1...n個方法,能夠是抽象的,也能夠是實際的方法,定義一個類,繼承該抽象類,重寫抽象方法,經過調用抽象類,實現對子類的調用,先看個關係圖:

就是在AbstractCalculator類中定義一個主方法calculate,calculate()調用spilt()等,Plus和Minus分別繼承AbstractCalculator類,經過對AbstractCalculator的調用實現對子類的調用,看下面的例子:

[java] view plaincopy

  1. public abstract class AbstractCalculator {  

  2.       

  3.     /*主方法,實現對本類其它方法的調用*/  

  4.     public final int calculate(String exp,String opt){  

  5.         int array[] = split(exp,opt);  

  6.         return calculate(array[0],array[1]);  

  7.     }  

  8.       

  9.     /*被子類重寫的方法*/  

  10.     abstract public int calculate(int num1,int num2);  

  11.       

  12.     public int[] split(String exp,String opt){  

  13.         String array[] = exp.split(opt);  

  14.         int arrayInt[] = new int[2];  

  15.         arrayInt[0] = Integer.parseInt(array[0]);  

  16.         arrayInt[1] = Integer.parseInt(array[1]);  

  17.         return arrayInt;  

  18.     }  

  19. }  

[java] view plaincopy

  1. public class Plus extends AbstractCalculator {  

  2.   

  3.     @Override  

  4.     public int calculate(int num1,int num2) {  

  5.         return num1 + num2;  

  6.     }  

  7. }  

測試類:

[java] view plaincopy

  1. public class StrategyTest {  

  2.   

  3.     public static void main(String[] args) {  

  4.         String exp = "8+8";  

  5.         AbstractCalculator cal = new Plus();  

  6.         int result = cal.calculate(exp, "\\+");  

  7.         System.out.println(result);  

  8.     }  

  9. }  

我跟蹤下這個小程序的執行過程:首先將exp和"\\+"作參數,調用AbstractCalculator類裏的calculate(String,String)方法,在calculate(String,String)裏調用同類的split(),以後再調用calculate(int ,int)方法,從這個方法進入到子類中,執行完return num1 + num2後,將值返回到AbstractCalculator類,賦給result,打印出來。正好驗證了咱們開頭的思路。


1五、觀察者模式(Observer)

包括這個模式在內的接下來的四個模式,都是類和類之間的關係,不涉及到繼承,學的時候應該 記得概括,記得本文最開始的那個圖。觀察者模式很好理解,相似於郵件訂閱和RSS訂閱,當咱們瀏覽一些博客或wiki時,常常會看到RSS圖標,就這的意思是,當你訂閱了該文章,若是後續有更新,會及時通知你。其實,簡單來說就一句話:當一個對象變化時,其它依賴該對象的對象都會收到通知,而且隨着變化!對象之間是一種一對多的關係。先來看看關係圖:

我解釋下這些類的做用:MySubject類就是咱們的主對象,Observer1和Observer2是依賴於MySubject的對象,當MySubject變化時,Observer1和Observer2必然變化。AbstractSubject類中定義着須要監控的對象列表,能夠對其進行修改:增長或刪除被監控對象,且當MySubject變化時,負責通知在列表內存在的對象。咱們看實現代碼:

一個Observer接口:

[java] view plaincopy

  1. public interface Observer {  

  2.     public void update();  

  3. }  

兩個實現類:

[java] view plaincopy

  1. public class Observer1 implements Observer {  

  2.   

  3.     @Override  

  4.     public void update() {  

  5.         System.out.println("observer1 has received!");  

  6.     }  

  7. }  

[java] view plaincopy

  1. public class Observer2 implements Observer {  

  2.   

  3.     @Override  

  4.     public void update() {  

  5.         System.out.println("observer2 has received!");  

  6.     }  

  7.   

  8. }  

Subject接口及實現類:

[java] view plaincopy

  1. public interface Subject {  

  2.       

  3.     /*增長觀察者*/  

  4.     public void add(Observer observer);  

  5.       

  6.     /*刪除觀察者*/  

  7.     public void del(Observer observer);  

  8.       

  9.     /*通知全部的觀察者*/  

  10.     public void notifyObservers();  

  11.       

  12.     /*自身的操做*/  

  13.     public void operation();  

  14. }  

[java] view plaincopy

  1. public abstract class AbstractSubject implements Subject {  

  2.   

  3.     private Vector<Observer> vector = new Vector<Observer>();  

  4.     @Override  

  5.     public void add(Observer observer) {  

  6.         vector.add(observer);  

  7.     }  

  8.   

  9.     @Override  

  10.     public void del(Observer observer) {  

  11.         vector.remove(observer);  

  12.     }  

  13.   

  14.     @Override  

  15.     public void notifyObservers() {  

  16.         Enumeration<Observer> enumo = vector.elements();  

  17.         while(enumo.hasMoreElements()){  

  18.             enumo.nextElement().update();  

  19.         }  

  20.     }  

  21. }  

[java] view plaincopy

  1. public class MySubject extends AbstractSubject {  

  2.   

  3.     @Override  

  4.     public void operation() {  

  5.         System.out.println("update self!");  

  6.         notifyObservers();  

  7.     }  

  8.   

  9. }  


測試類:

[java] view plaincopy

  1. public class ObserverTest {  

  2.   

  3.     public static void main(String[] args) {  

  4.         Subject sub = new MySubject();  

  5.         sub.add(new Observer1());  

  6.         sub.add(new Observer2());  

  7.           

  8.         sub.operation();  

  9.     }  

  10.   

  11. }  

輸出:

update self!
observer1 has received!
observer2 has received!

 這些東西,其實不難,只是有些抽象,不太容易總體理解,建議讀者:根據關係圖,新建項目,本身寫代碼(或者參考個人代碼),按照整體思路走一遍,這樣才能體會它的思想,理解起來容易! 


1六、迭代子模式(Iterator)

顧名思義,迭代器模式就是順序訪問彙集中的對象,通常來講,集合中很是常見,若是對集合類比較熟悉的話,理解本模式會十分輕鬆。這句話包含兩層意思:一是須要遍歷的對象,即彙集對象,二是迭代器對象,用於對彙集對象進行遍歷訪問。咱們看下關係圖:

 

這個思路和咱們經常使用的如出一轍,MyCollection中定義了集合的一些操做,MyIterator中定義了一系列迭代操做,且持有Collection實例,咱們來看看實現代碼:

兩個接口:

[java] view plaincopy

  1. public interface Collection {  

  2.       

  3.     public Iterator iterator();  

  4.       

  5.     /*取得集合元素*/  

  6.     public Object get(int i);  

  7.       

  8.     /*取得集合大小*/  

  9.     public int size();  

  10. }  

[java] view plaincopy

  1. public interface Iterator {  

  2.     //前移  

  3.     public Object previous();  

  4.       

  5.     //後移  

  6.     public Object next();  

  7.     public boolean hasNext();  

  8.       

  9.     //取得第一個元素  

  10.     public Object first();  

  11. }  

兩個實現:

[java] view plaincopy

  1. public class MyCollection implements Collection {  

  2.   

  3.     public String string[] = {"A","B","C","D","E"};  

  4.     @Override  

  5.     public Iterator iterator() {  

  6.         return new MyIterator(this);  

  7.     }  

  8.   

  9.     @Override  

  10.     public Object get(int i) {  

  11.         return string[i];  

  12.     }  

  13.   

  14.     @Override  

  15.     public int size() {  

  16.         return string.length;  

  17.     }  

  18. }  

[java] view plaincopy

  1. public class MyIterator implements Iterator {  

  2.   

  3.     private Collection collection;  

  4.     private int pos = -1;  

  5.       

  6.     public MyIterator(Collection collection){  

  7.         this.collection = collection;  

  8.     }  

  9.       

  10.     @Override  

  11.     public Object previous() {  

  12.         if(pos > 0){  

  13.             pos--;  

  14.         }  

  15.         return collection.get(pos);  

  16.     }  

  17.   

  18.     @Override  

  19.     public Object next() {  

  20.         if(pos<collection.size()-1){  

  21.             pos++;  

  22.         }  

  23.         return collection.get(pos);  

  24.     }  

  25.   

  26.     @Override  

  27.     public boolean hasNext() {  

  28.         if(pos<collection.size()-1){  

  29.             return true;  

  30.         }else{  

  31.             return false;  

  32.         }  

  33.     }  

  34.   

  35.     @Override  

  36.     public Object first() {  

  37.         pos = 0;  

  38.         return collection.get(pos);  

  39.     }  

  40.   

  41. }  

測試類:

[java] view plaincopy

  1. public class Test {  

  2.   

  3.     public static void main(String[] args) {  

  4.         Collection collection = new MyCollection();  

  5.         Iterator it = collection.iterator();  

  6.           

  7.         while(it.hasNext()){  

  8.             System.out.println(it.next());  

  9.         }  

  10.     }  

  11. }  

輸出:A B C D E

此處咱們貌似模擬了一個集合類的過程,感受是否是很爽?其實JDK中各個類也都是這些基本的東西,加一些設計模式,再加一些優化放到一塊兒的,只要咱們把這些東西學會了,掌握好了,咱們也能夠寫出本身的集合類,甚至框架!


1七、責任鏈模式(Chain of Responsibility)
接下來咱們將要談談責任鏈模式,有多個對象,每一個對象持有對下一個對象的引用,這樣就會造成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。可是發出者並不清楚到底最終那個對象會處理該請求,因此,責任鏈模式能夠實現,在隱瞞客戶端的狀況下,對系統進行動態的調整。先看看關係圖:

 

 

Abstracthandler類提供了get和set方法,方便MyHandle類設置和修改引用對象,MyHandle類是核心,實例化後生成一系列相互持有的對象,構成一條鏈。

[java] view plaincopy

  1. public interface Handler {  

  2.     public void operator();  

  3. }  

[java] view plaincopy

  1. public abstract class AbstractHandler {  

  2.       

  3.     private Handler handler;  

  4.   

  5.     public Handler getHandler() {  

  6.         return handler;  

  7.     }  

  8.   

  9.     public void setHandler(Handler handler) {  

  10.         this.handler = handler;  

  11.     }  

  12.       

  13. }  

[java] view plaincopy

  1. public class MyHandler extends AbstractHandler implements Handler {  

  2.   

  3.     private String name;  

  4.   

  5.     public MyHandler(String name) {  

  6.         this.name = name;  

  7.     }  

  8.   

  9.     @Override  

  10.     public void operator() {  

  11.         System.out.println(name+"deal!");  

  12.         if(getHandler()!=null){  

  13.             getHandler().operator();  

  14.         }  

  15.     }  

  16. }  

[java] view plaincopy

  1. public class Test {  

  2.   

  3.     public static void main(String[] args) {  

  4.         MyHandler h1 = new MyHandler("h1");  

  5.         MyHandler h2 = new MyHandler("h2");  

  6.         MyHandler h3 = new MyHandler("h3");  

  7.   

  8.         h1.setHandler(h2);  

  9.         h2.setHandler(h3);  

  10.   

  11.         h1.operator();  

  12.     }  

  13. }  

輸出:

h1deal!
h2deal!
h3deal!

此處強調一點就是,連接上的請求能夠是一條鏈,能夠是一個樹,還能夠是一個環,模式自己不約束這個,須要咱們本身去實現,同時,在一個時刻,命令只容許由一個對象傳給另外一個對象,而不容許傳給多個對象。


 1八、命令模式(Command)

命令模式很好理解,舉個例子,司令員下令讓士兵去幹件事情,從整個事情的角度來考慮,司令員的做用是,發出口令,口令通過傳遞,傳到了士兵耳朵裏,士兵去執行。這個過程好在,三者相互解耦,任何一方都不用去依賴其餘人,只須要作好本身的事兒就行,司令員要的是結果,不會去關注到底士兵是怎麼實現的。咱們看看關係圖:

Invoker是調用者(司令員),Receiver是被調用者(士兵),MyCommand是命令,實現了Command接口,持有接收對象,看實現代碼:

[java] view plaincopy

  1. public interface Command {  

  2.     public void exe();  

  3. }  

[java] view plaincopy

  1. public class MyCommand implements Command {  

  2.   

  3.     private Receiver receiver;  

  4.       

  5.     public MyCommand(Receiver receiver) {  

  6.         this.receiver = receiver;  

  7.     }  

  8.   

  9.     @Override  

  10.     public void exe() {  

  11.         receiver.action();  

  12.     }  

  13. }  

[java] view plaincopy

  1. public class Receiver {  

  2.     public void action(){  

  3.         System.out.println("command received!");  

  4.     }  

  5. }  

[java] view plaincopy

  1. public class Invoker {  

  2.       

  3.     private Command command;  

  4.       

  5.     public Invoker(Command command) {  

  6.         this.command = command;  

  7.     }  

  8.   

  9.     public void action(){  

  10.         command.exe();  

  11.     }  

  12. }  

[java] view plaincopy

  1. public class Test {  

  2.   

  3.     public static void main(String[] args) {  

  4.         Receiver receiver = new Receiver();  

  5.         Command cmd = new MyCommand(receiver);  

  6.         Invoker invoker = new Invoker(cmd);  

  7.         invoker.action();  

  8.     }  

  9. }  

輸出:command received!

這個很哈理解,命令模式的目的就是達到命令的發出者和執行者之間解耦,實現請求和執行分開,熟悉Struts的同窗應該知道,Struts其實就是一種將請求和呈現分離的技術,其中必然涉及命令模式的思想!

其實每一個設計模式都是很重要的一種思想,看上去很熟,實際上是由於咱們在學到的東西中都有涉及,儘管有時咱們並不知道,其實在Java自己的設計之中到處都有體現,像AWT、JDBC、集合類、IO管道或者是Web框架,裏面設計模式無處不在。由於咱們篇幅有限,很難講每個設計模式都講的很詳細,不過我會盡我所能,儘可能在有限的空間和篇幅內,把意思寫清楚了,更好讓你們明白。本章不出意外的話,應該是設計模式最後一講了,首先仍是上一下上篇開頭的那個圖:

本章講講第三類和第四類。


1九、備忘錄模式(Memento)

主要目的是保存一個對象的某個狀態,以便在適當的時候恢復對象,我的以爲叫備份模式更形象些,通俗的講下:假設有原始類A,A中有各類屬性,A能夠決定須要備份的屬性,備忘錄類B是用來存儲A的一些內部狀態,類C呢,就是一個用來存儲備忘錄的,且只能存儲,不能修改等操做。作個圖來分析一下:

Original類是原始類,裏面有須要保存的屬性value及建立一個備忘錄類,用來保存value值。Memento類是備忘錄類,Storage類是存儲備忘錄的類,持有Memento類的實例,該模式很好理解。直接看源碼:

[java] view plaincopy

  1. public class Original {  

  2.       

  3.     private String value;  

  4.       

  5.     public String getValue() {  

  6.         return value;  

  7.     }  

  8.   

  9.     public void setValue(String value) {  

  10.         this.value = value;  

  11.     }  

  12.   

  13.     public Original(String value) {  

  14.         this.value = value;  

  15.     }  

  16.   

  17.     public Memento createMemento(){  

  18.         return new Memento(value);  

  19.     }  

  20.       

  21.     public void restoreMemento(Memento memento){  

  22.         this.value = memento.getValue();  

  23.     }  

  24. }  

[java] view plaincopy

  1. public class Memento {  

  2.       

  3.     private String value;  

  4.   

  5.     public Memento(String value) {  

  6.         this.value = value;  

  7.     }  

  8.   

  9.     public String getValue() {  

  10.         return value;  

  11.     }  

  12.   

  13.     public void setValue(String value) {  

  14.         this.value = value;  

  15.     }  

  16. }  

[java] view plaincopy

  1. public class Storage {  

  2.       

  3.     private Memento memento;  

  4.       

  5.     public Storage(Memento memento) {  

  6.         this.memento = memento;  

  7.     }  

  8.   

  9.     public Memento getMemento() {  

  10.         return memento;  

  11.     }  

  12.   

  13.     public void setMemento(Memento memento) {  

  14.         this.memento = memento;  

  15.     }  

  16. }  

測試類:

[java] view plaincopy

  1. public class Test {  

  2.   

  3.     public static void main(String[] args) {  

  4.           

  5.         // 建立原始類  

  6.         Original origi = new Original("egg");  

  7.   

  8.         // 建立備忘錄  

  9.         Storage storage = new Storage(origi.createMemento());  

  10.   

  11.         // 修改原始類的狀態  

  12.         System.out.println("初始化狀態爲:" + origi.getValue());  

  13.         origi.setValue("niu");  

  14.         System.out.println("修改後的狀態爲:" + origi.getValue());  

  15.   

  16.         // 回覆原始類的狀態  

  17.         origi.restoreMemento(storage.getMemento());  

  18.         System.out.println("恢復後的狀態爲:" + origi.getValue());  

  19.     }  

  20. }  

輸出:

初始化狀態爲:egg
修改後的狀態爲:niu
恢復後的狀態爲:egg

簡單描述下:新建原始類時,value被初始化爲egg,後通過修改,將value的值置爲niu,最後倒數第二行進行恢復狀態,結果成功恢復了。其實我以爲這個模式叫「備份-恢復」模式最形象。

相關文章
相關標籤/搜索