Java中的23種設計模式(四)

(備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式)
原文作者:終點 出處:Java之美[從菜鳥到高手演變]之設計模式四

首先還是上一下上篇開頭的那個圖:



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

19、備忘錄模式(Memento)
備忘錄模式

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

public class Original {
    
    private String value;
    
    public String getValue() {
        return value;
    }
 
    public void setValue(String value) {
        this.value = value;
    }
 
    public Original(String value) {
        this.value = value;
    }
 
    public Memento createMemento(){
        return new Memento(value);
    }
    
    public void restoreMemento(Memento memento){
        this.value = memento.getValue();
    }
}

public class Memento {
    
    private String value;
 
    public Memento(String value) {
        this.value = value;
    }
 
    public String getValue() {
        return value;
    }
 
    public void setValue(String value) {
        this.value = value;
    }
}

public class Storage {
    
    private Memento memento;
    
    public Storage(Memento memento) {
        this.memento = memento;
    }
 
    public Memento getMemento() {
        return memento;
    }
 
    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

測試類:

public class Test {
 
    public static void main(String[] args) {
        
        // 創建原始類
        Original origi = new Original("egg");
 
        // 創建備忘錄
        Storage storage = new Storage(origi.createMemento());
 
        // 修改原始類的狀態
        System.out.println("初始化狀態為:" + origi.getValue());
        origi.setValue("niu");
        System.out.println("修改后的狀態為:" + origi.getValue());
 
        // 回復原始類的狀態
        origi.restoreMemento(storage.getMemento());
        System.out.println("恢復后的狀態為:" + origi.getValue());
    }
}

輸出:

初始化狀態為:egg
修改后的狀態為:niu
恢復后的狀態為:egg

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

20、狀態模式(State)

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


狀態模式

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

package com.xtfggef.dp.state;
 
/**
 * 狀態類的核心類
 * 2012-12-1
 * @author erqing
 *
 */
public class State {
    
    private String value;
    
    public String getValue() {
        return value;
    }
 
    public void setValue(String value) {
        this.value = value;
    }
 
    public void method1(){
        System.out.println("execute the first opt!");
    }
    
    public void method2(){
        System.out.println("execute the second opt!");
    }
}
package com.xtfggef.dp.state;
 
/**
 * 狀態模式的切換類   2012-12-1
 * @author erqing
 * 
 */
public class Context {
 
    private State state;
 
    public Context(State state) {
        this.state = state;
    }
 
    public State getState() {
        return state;
    }
 
    public void setState(State state) {
        this.state = state;
    }
 
    public void method() {
        if (state.getValue().equals("state1")) {
            state.method1();
        } else if (state.getValue().equals("state2")) {
            state.method2();
        }
    }
}

測試類:

public class Test {
 
    public static void main(String[] args) {
        
        State state = new State();
        Context context = new Context(state);
        
        //設置第一種狀態
        state.setValue("state1");
        context.method();
        
        //設置第二種狀態
        state.setValue("state2");
        context.method();
    }
}

輸出:
execute the first opt!
execute the second opt!

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

21、訪問者模式(Visitor)

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

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


訪問者模式

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

public interface Visitor {
    public void visit(Subject sub);
}
public class MyVisitor implements Visitor {
 
    @Override
    public void visit(Subject sub) {
        System.out.println("visit the subject:"+sub.getSubject());
    }
}

Subject類,accept方法,接受將要訪問它的對象,getSubject()獲取將要被訪問的屬性,

public interface Subject {
    public void accept(Visitor visitor);
    public String getSubject();
}
public class MySubject implements Subject {
 
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
 
    @Override
    public String getSubject() {
        return "love";
    }
}

測試:

public class Test {
 
    public static void main(String[] args) {
        
        Visitor visitor = new MyVisitor();
        Subject sub = new MySubject();
        sub.accept(visitor);    
    }
}

輸出: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類來維護!基本實現:

public interface Mediator {
    public void createMediator();
    public void workAll();
}
public class MyMediator implements Mediator {
 
    private User user1;
    private User user2;
    
    public User getUser1() {
        return user1;
    }
 
    public User getUser2() {
        return user2;
    }
 
    @Override
    public void createMediator() {
        user1 = new User1(this);
        user2 = new User2(this);
    }
 
    @Override
    public void workAll() {
        user1.work();
        user2.work();
    }
}
public abstract class User {
    
    private Mediator mediator;
    
    public Mediator getMediator(){
        return mediator;
    }
    
    public User(Mediator mediator) {
        this.mediator = mediator;
    }
 
    public abstract void work();
}
public class User1 extends User {
 
    public User1(Mediator mediator){
        super(mediator);
    }
    
    @Override
    public void work() {
        System.out.println("user1 exe!");
    }
}
public class User1 extends User {
 
    public User1(Mediator mediator){
        super(mediator);
    }
    
    @Override
    public void work() {
        System.out.println("user1 exe!");
    }
}
public class User2 extends User {
 
    public User2(Mediator mediator){
        super(mediator);
    }
    
    @Override
    public void work() {
        System.out.println("user2 exe!");
    }
}

測試類:

public class Test {
 
    public static void main(String[] args) {
        Mediator mediator = new MyMediator();
        mediator.createMediator();
        mediator.workAll();
    }
}

輸出:
user1 exe!
user2 exe!

23、解釋器模式(Interpreter)

解釋器模式一般主要應用在OOP開發中的編譯器的開發中,所以適用面比較窄。


解釋器模式

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

public interface Expression {
    public int interpret(Context context);
}
public class Plus implements Expression {
 
    @Override
    public int interpret(Context context) {
        return context.getNum1()+context.getNum2();
    }
}
public class Minus implements Expression {
 
    @Override
    public int interpret(Context context) {
        return context.getNum1()-context.getNum2();
    }
}
public class Context {
    
    private int num1;
    private int num2;
    
    public Context(int num1, int num2) {
        this.num1 = num1;
        this.num2 = num2;
    }
    
    public int getNum1() {
        return num1;
    }
    public void setNum1(int num1) {
        this.num1 = num1;
    }
    public int getNum2() {
        return num2;
    }
    public void setNum2(int num2) {
        this.num2 = num2;
    }   
}
public class Test {
 
    public static void main(String[] args) {
 
        // 計算9+2-8的值
        int result = new Minus().interpret((new Context(new Plus()
                .interpret(new Context(9, 2)), 8)));
        System.out.println(result);
    }
}

最后輸出正確的結果:3。

23種設計模式,完。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375