Java之美[從菜鳥到高手演變]之設計模式四

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

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

19、備忘錄模式(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,最後倒數第二行進行恢復狀態,結果成功恢復了。其實我覺得這個模式叫“備份-恢復”模式最形象。

20、狀態模式(State)

核心思想就是:當對象的狀態改變時,同時改變其行爲,很好理解!就拿QQ來說,有幾種狀態,在線、隱身、忙碌等,每個狀態對應不同的操作,而且你的好友也能看到你的狀態,所以,狀態模式就兩點:1、可以通過改變狀態來獲得不同的行爲。2、你的好友能同時看到你的變化。看圖:


State類是個狀態類,Context類可以實現切換,我們來看看代碼:

[java] view plaincopy
  1. package com.xtfggef.dp.state;  
  2.   
  3. /** 
  4.  * 狀態類的核心類 
  5.  * 2012-12-1 
  6.  * @author erqing 
  7.  * 
  8.  */  
  9. public class State {  
  10.       
  11.     private String value;  
  12.       
  13.     public String getValue() {  
  14.         return value;  
  15.     }  
  16.   
  17.     public void setValue(String value) {  
  18.         this.value = value;  
  19.     }  
  20.   
  21.     public void method1(){  
  22.         System.out.println("execute the first opt!");  
  23.     }  
  24.       
  25.     public void method2(){  
  26.         System.out.println("execute the second opt!");  
  27.     }  
  28. }  
[java] view plaincopy
  1. package com.xtfggef.dp.state;  
  2.   
  3. /** 
  4.  * 狀態模式的切換類   2012-12-1 
  5.  * @author erqing 
  6.  *  
  7.  */  
  8. public class Context {  
  9.   
  10.     private State state;  
  11.   
  12.     public Context(State state) {  
  13.         this.state = state;  
  14.     }  
  15.   
  16.     public State getState() {  
  17.         return state;  
  18.     }  
  19.   
  20.     public void setState(State state) {  
  21.         this.state = state;  
  22.     }  
  23.   
  24.     public void method() {  
  25.         if (state.getValue().equals("state1")) {  
  26.             state.method1();  
  27.         } else if (state.getValue().equals("state2")) {  
  28.             state.method2();  
  29.         }  
  30.     }  
  31. }  
測試類:

[java] view plaincopy
  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.           
  5.         State state = new State();  
  6.         Context context = new Context(state);  
  7.           
  8.         //設置第一種狀態  
  9.         state.setValue("state1");  
  10.         context.method();  
  11.           
  12.         //設置第二種狀態  
  13.         state.setValue("state2");  
  14.         context.method();  
  15.     }  
  16. }  
輸出:

execute the first opt!
execute the second opt!

根據這個特性,狀態模式在日常開發中用的挺多的,尤其是做網站的時候,我們有時希望根據對象的某一屬性,區別開他們的一些功能,比如說簡單的權限控制等。
21、訪問者模式(Visitor)

訪問者模式把數據結構和作用於結構上的操作解耦合,使得操作集合可相對自由地演化。訪問者模式適用於數據結構相對穩定算法又易變化的系統。因爲訪問者模式使得算法操作增加變得容易。若系統數據結構對象易於變化,經常有新的數據對象增加進來,則不適合使用訪問者模式。訪問者模式的優點是增加操作很容易,因爲增加操作意味着增加新的訪問者。訪問者模式將有關行爲集中到一個訪問者對象中,其改變不影響系統數據結構。其缺點就是增加新的數據結構很困難。—— From 百科

簡單來說,訪問者模式就是一種分離對象數據結構與行爲的方法,通過這種分離,可達到爲一個被訪問者動態添加新的操作而無需做其它的修改的效果。簡單關係圖:


來看看原碼:一個Visitor類,存放要訪問的對象,

[java] view plaincopy
  1. public interface Visitor {  
  2.     public void visit(Subject sub);  
  3. }  
[java] view plaincopy
  1. public class MyVisitor implements Visitor {  
  2.   
  3.     @Override  
  4.     public void visit(Subject sub) {  
  5.         System.out.println("visit the subject:"+sub.getSubject());  
  6.     }  
  7. }  
Subject類,accept方法,接受將要訪問它的對象,getSubject()獲取將要被訪問的屬性,
[java] view plaincopy
  1. public interface Subject {  
  2.     public void accept(Visitor visitor);  
  3.     public String getSubject();  
  4. }  
[java] view plaincopy
  1. public class MySubject implements Subject {  
  2.   
  3.     @Override  
  4.     public void accept(Visitor visitor) {  
  5.         visitor.visit(this);  
  6.     }  
  7.   
  8.     @Override  
  9.     public String getSubject() {  
  10.         return "love";  
  11.     }  
  12. }  
測試:

[java] view plaincopy
  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.           
  5.         Visitor visitor = new MyVisitor();  
  6.         Subject sub = new MySubject();  
  7.         sub.accept(visitor);      
  8.     }  
  9. }  
輸出:visit the subject:love

該模式適用場景:如果我們想爲一個現有的類增加新功能,不得不考慮幾個事情:1、新功能會不會與現有功能出現兼容性問題?2、以後會不會再需要添加?3、如果類不允許修改代碼怎麼辦?面對這些問題,最好的解決方法就是使用訪問者模式,訪問者模式適用於數據結構相對穩定的系統,把數據結構和算法解耦,
22、中介者模式(Mediator)

中介者模式也是用來降低類類之間的耦合的,因爲如果類類之間有依賴關係的話,不利於功能的拓展和維護,因爲只要修改一個對象,其它關聯的對象都得進行修改。如果使用中介者模式,只需關心和Mediator類的關係,具體類類之間的關係及調度交給Mediator就行,這有點像spring容器的作用。先看看圖:


User類統一接口,User1和User2分別是不同的對象,二者之間有關聯,如果不採用中介者模式,則需要二者相互持有引用,這樣二者的耦合度很高,爲了解耦,引入了Mediator類,提供統一接口,MyMediator爲其實現類,裏面持有User1和User2的實例,用來實現對User1和User2的控制。這樣User1和User2兩個對象相互獨立,他們只需要保持好和Mediator之間的關係就行,剩下的全由MyMediator類來維護!基本實現:

[java] view plaincopy
  1. public interface Mediator {  
  2.     public void createMediator();  
  3.     public void workAll();  
  4. }  
[java] view plaincopy
  1. public class MyMediator implements Mediator {  
  2.   
  3.     private User user1;  
  4.     private User user2;  
  5.       
  6.     public User getUser1() {  
  7.         return user1;  
  8.     }  
  9.   
  10.     public User getUser2() {  
  11.         return user2;  
  12.     }  
  13.   
  14.     @Override  
  15.     public void createMediator() {  
  16.         user1 = new User1(this);  
  17.         user2 = new User2(this);  
  18.     }  
  19.   
  20.     @Override  
  21.     public void workAll() {  
  22.         user1.work();  
  23.         user2.work();  
  24.     }  
  25. }  
[java] view plaincopy
  1. public abstract class User {  
  2.       
  3.     private Mediator mediator;  
  4.       
  5.     public Mediator getMediator(){  
  6.         return mediator;  
  7.     }  
  8.       
  9.     public User(Mediator mediator) {  
  10.         this.mediator = mediator;  
  11.     }  
  12.   
  13.     public abstract void work();  
  14. }  
[java] view plaincopy
  1. public class User1 extends User {  
  2.   
  3.     public User1(Mediator mediator){  
  4.         super(mediator);  
  5.     }  
  6.       
  7.     @Override  
  8.     public void work() {  
  9.         System.out.println("user1 exe!");  
  10.     }  
  11. }  
[java] view plaincopy
  1. public class User2 extends User {  
  2.   
  3.     public User2(Mediator mediator){  
  4.         super(mediator);  
  5.     }  
  6.       
  7.     @Override  
  8.     public void work() {  
  9.         System.out.println("user2 exe!");  
  10.     }  
  11. }  
測試類:

[java] view plaincopy
  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.         Mediator mediator = new MyMediator();  
  5.         mediator.createMediator();  
  6.         mediator.workAll();  
  7.     }  
  8. }  
輸出:

user1 exe!
user2 exe!
23、解釋器模式(Interpreter)
解釋器模式是我們暫時的最後一講,一般主要應用在OOP開發中的編譯器的開發中,所以適用面比較窄。


Context類是一個上下文環境類,Plus和Minus分別是用來計算的實現,代碼如下:

[java] view plaincopy
  1. public interface Expression {  
  2.     public int interpret(Context context);  
  3. }  
[java] view plaincopy
  1. public class Plus implements Expression {  
  2.   
  3.     @Override  
  4.     public int interpret(Context context) {  
  5.         return context.getNum1()+context.getNum2();  
  6.     }  
  7. }  
[java] view plaincopy
  1. public class Minus implements Expression {  
  2.   
  3.     @Override  
  4.     public int interpret(Context context) {  
  5.         return context.getNum1()-context.getNum2();  
  6.     }  
  7. }  
[java] view plaincopy
  1. public class Context {  
  2.       
  3.     private int num1;  
  4.     private int num2;  
  5.       
  6.     public Context(int num1, int num2) {  
  7.         this.num1 = num1;  
  8.         this.num2 = num2;  
  9.     }  
  10.       
  11.     public int getNum1() {  
  12.         return num1;  
  13.     }  
  14.     public void setNum1(int num1) {  
  15.         this.num1 = num1;  
  16.     }  
  17.     public int getNum2() {  
  18.         return num2;  
  19.     }  
  20.     public void setNum2(int num2) {  
  21.         this.num2 = num2;  
  22.     }  
  23.       
  24.       
  25. }  
[java] view plaincopy
  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.   
  5.         // 計算9+2-8的值  
  6.         int result = new Minus().interpret((new Context(new Plus()  
  7.                 .interpret(new Context(92)), 8)));  
  8.         System.out.println(result);  
  9.     }  
  10. }  
最後輸出正確的結果:3。

基本就這樣,解釋器模式用來做各種各樣的解釋器,如正則表達式等的解釋器等等!

設計模式基本就這麼大概講完了,總體感覺有點簡略,的確,這麼點兒篇幅,不足以對整個23種設計模式做全面的闡述,此處讀者可將它作爲一個理論基礎去學習,通過這四篇博文,先基本有個概念,雖然我講的有些簡單,但基本都能說明問題及他們的特點,如果對哪一個感興趣,可以繼續深入研究!同時我也會不斷更新,儘量補全遺漏、修正不足,歡迎廣大讀者及時提出好的建議,我們一起學習!項目中涉及到的代碼,已經放到了我的資源裏:http://download.csdn.net/detail/zhangerqing/4835830(因爲我不喜歡不勞而獲,所以沒有免積分,只設置了5個,如果有人實在沒積分又急要,那麼聯繫我吧,我給你發過去)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章