天天看點

具體的設計模式(三):行為型模式

行為型模式:

有11種:政策模式,模闆方法,觀察者模式,疊代子模式,責任鍊模式,指令模式,備忘錄模式,狀态模式,通路者模式,中介者模式,解釋器模式。

先來張圖,看看這11中模式的關系:

第一類:通過父類與子類的關系進行實作。第二類:兩個類之間。第三類:類的狀态。第四類:通過中間類。

具體的設計模式(三):行為型模式

13.政策模式(Strategy)

簡單說明:定義一系列的算法,把它們一個個封裝起來,并且使他們可互相替換。

應用執行個體:

  1. 諸葛亮的錦囊妙計,每一個錦囊就是一個政策
  2. 旅行的出遊方式,選擇騎自行車、坐汽車,每一種旅行方式都是一個政策

舉例說明:

設計一個政策的接口

package strategy;

/**
 * 政策模式: 一個類的行為或其算法可以在運作時更改。行為類設計模式
 * 設計一個接口,然後寫不同的政策實作類,這些實作類,實作同一接口
 * 意圖:定義一系列的算法,把他們一個一個封裝起來,并且使它們可互相替換
 * 在多種算法相似的情況下,使用if...else所帶來的複雜和難以維護。
 * 
 * 應用執行個體: 1、諸葛亮的錦囊妙計,每一個錦囊就是一個政策。 
 *        2、旅行的出遊方式,選擇騎自行車、坐汽車,每一種旅行方式都是一個政策。
 *        3、JAVA AWT 中的 LayoutManager。
 * @author cx
 * 優點: 1、算法可以自由切換。 2、避免使用多重條件判斷。 3、擴充性良好。
         缺點: 1、政策類會增多。 2、所有政策類都需要對外暴露。
 */

public interface Strategy {

    public int doOperation(int num1,int num2);
}
           

加法政策

package strategy;

public class OperationAdd implements Strategy{

    //實作加法
    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自動生成的方法存根
        return num1+num2;
    }

}
           

減法政策

package strategy;

public class OperationSubstract implements Strategy{

    //實作減法
    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自動生成的方法存根
        return num1-num2;
    }

}
           

乘法政策

package strategy;

public class OperationMultiply implements Strategy{

    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自動生成的方法存根
        return num1*num2;
    }

}
           

除法政策

package strategy;

public class OperationDivision implements Strategy{

    //除法
    @Override
    public int doOperation(int num1, int num2) {
        // TODO 自動生成的方法存根
        return num1/num2;
    }

}
           

執行政策的類

package strategy;

public class Context {

    private Strategy strategy;

    public Context(Strategy strategy){
        this.strategy=strategy;
    }

    public int executeStrategy(int num1,int num2){
        return strategy.doOperation(num1,num2);
    }
}
           

測試Test

package strategy;

public class Test {

    public static void main(String[] args) {
        int num1=,num2=;

        Context context=new Context(new OperationAdd());
        System.out.println("10+5="+context.executeStrategy(num1, num2));

        context=new Context(new OperationSubstract());
        System.out.println("10-5="+context.executeStrategy(num1, num2));

        context=new Context(new OperationMultiply());
        System.out.println("10*5="+context.executeStrategy(num1, num2));

        context=new Context(new OperationDivision());
        System.out.println("10/5="+context.executeStrategy(num1, num2));
    }
}
           

測試結果

10+5=15
10-5=5
10*5=50
10/5=2

           

14.模闆方法(Template)

簡單說明:一個抽象類公開定義了執行它的方法的方式/模闆。它的子類可以按需要重寫方法實作,但調用将以抽象類中定義的方式進行。

意圖:定義一個操作中的算法的骨架,而将一些步驟延遲到子類中。模闆方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

舉例說明:

設計一個Game抽象類模闆,并定義了一些抽象方法,和一些非抽象方法(在非抽象方法中,定義了抽象方法的執行順序)

package template;

/**
 * 模闆模式:一個抽象類公開定義了執行它的方法的方式/模闆。它的子類可以按需求重寫方法實作。
 * @author cx
 * 意圖:定義了一個操作中的算法的骨架,而将一些步驟延遲到子類中。模闆方法使得子類可以不改變一個算法的結構
 *      即可重新定義該算法的某些特定步驟。
 * 關鍵:在抽象類中定義一個final的具體方法,用來歸束抽象類中抽象方法的執行結構(順序).
 *     然後在子類中,讓其自動生成抽象類中定義的那些模闆方法
 * 
 * 優點: 1、封裝不變部分,擴充可變部分。 2、提取公共代碼,便于維護。 3、行為由父類控制,子類實作。
         缺點:每一個不同的實作都需要一個子類來實作,導緻類的個數增加,使得系統更加龐大。

         使用場景: 1、有多個子類共有的方法,且邏輯相同。 2、重要的、複雜的方法,可以考慮作為模闆方法。
         注意事項:為防止惡意操作,一般模闆方法都加上 final 關鍵詞。
 */


public abstract class Game {

    abstract void initialize();

    abstract void startPlay();

    abstract void endPlay();

    //模闆方法為final,不可重寫
    public final void play(){

        //初始化遊戲
        initialize();

        //開始遊戲
        startPlay();

        //結束遊戲
        endPlay();
    }
}
           

BasketballGame 子類繼承了Game抽象類,并實作了其抽象方法

package template;

public class BasketballGame extends Game{

    @Override
    void initialize() {
        // TODO 自動生成的方法存根
        System.out.println("basketball initialize...");
    }

    @Override
    void startPlay() {
        // TODO 自動生成的方法存根
        System.out.println("basketball startplay...");
    }

    @Override
    void endPlay() {
        // TODO 自動生成的方法存根
        System.out.println("basketball endplay...");
    }

}
           

FootballGame 子類繼承了Game抽象類,并實作了其抽象方法

package template;

public class FootballGame extends Game{

    @Override
    void initialize() {
        // TODO 自動生成的方法存根
        System.out.println("football initalize...");
    }

    @Override
    void startPlay() {
        // TODO 自動生成的方法存根
        System.out.println("football startplay...");
    }

    @Override
    void endPlay() {
        // TODO 自動生成的方法存根
        System.out.println("football endplay...");
    }

}
           

測試(Test)

package template;

public class Test {
    public static void main(String[] args) {

        Game game=new FootballGame();
        game.play();
        System.out.println("--------------------");
        game=new BasketballGame();
        game.play();
    }
}
           

測試結果

football initalize...
football startplay...
football endplay...
--------------------
basketball initialize...
basketball startplay...
basketball endplay...
           

15.觀察者模式(Observer)

簡單說明:當一個對象被修改時,則會通知它的依賴對象,并且所有依賴它的對象都得到通知并被自動更新。

執行個體說明:RxJava 中用到了觀察者模式,EventBus中也用到了觀察者模式。

舉例說明:

設計一個觀察者接口

package observer;

/**
 * 觀察者模式(Observer):當一個對象變化時,其他依賴該對象的對象都會收到通知,并且随着變化
 * 對象之間是一種一對多的關系
 * @author cx
 * 意圖:定義對象間的一種一對多的依賴關系,當一個對象的狀态改變時,所有依賴于它的對象都得到通知并被自動更新.
 * 關鍵:在AbstractSubscribe中有一個ArrayList存放的觀察者們
 * 
 * 應用執行個體:拍賣的時候,拍賣師觀察最高标價,然後通知給其他競價者競價
 * 
 * 
 *  優點: 1、觀察者和被觀察者是抽象耦合的。 2、建立一套觸發機制。
    缺點: 1、如果一個被觀察者對象有很多的直接和間接的觀察者的話,将所有的觀察者都通知到會花費很多時間。
         2、如果在觀察者和觀察目标之間有循環依賴的話,觀察目标會觸發它們之間進行循環調用,可能導緻系統崩潰。 3、觀察者模式沒有相應的機制讓觀察者知道所觀察的目标對象是怎麼發生變化的,而僅僅隻是知道觀察目标發生了變化。
    使用場景: 1、有多個子類共有的方法,且邏輯相同。 2、重要的、複雜的方法,可以考慮作為模闆方法。
    注意事項: 1、JAVA 中已經有了對觀察者模式的支援類。 2、避免循環引用。 
           3、如果順序執行,某一觀察者錯誤會導緻系統卡殼,一般采用異步方式。
 */
public interface Observer {

    public void update();
}
           

Observer1 觀察子接口1

package observer;


public class Observer1 implements Observer{

    @Override
    public void update() {
        // TODO 自動生成的方法存根
        System.out.println("Observer1 has received!");
    }

}
           

Observer2觀察子接口2

package observer;

public class Observer2 implements Observer{

    @Override
    public void update() {
        // TODO 自動生成的方法存根
        System.out.println("Observer2 has received!");
    }

}
           

訂閱者(包含所有對觀察者的操作)

package observer;

//訂閱者

public interface Subscribe {

    //增加觀察者
    public void add(Observer observer);

    //删除觀察者
    public void del(Observer observer);

    //通知所有的觀察者
    public void notifyObservers();

    //自身的操作
    public void operation();
}
           

抽象類AbstractSubscribe實作Subscribe接口,并加入集合ArrayList來存取Observer對象

package observer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

public abstract class AbstractSubscribe implements Subscribe{

    private List<Observer> list=new ArrayList<Observer>();

    @Override
    public void add(Observer observer) {
        // TODO 自動生成的方法存根
        list.add(observer);
    }

    @Override
    public void del(Observer observer) {
        // TODO 自動生成的方法存根
        list.remove(observer);
    }

    @Override
    public void notifyObservers() {
        // 用疊代器周遊 List集合中所有的Observer對象
        Iterator<Observer> iterator=list.iterator();
        while(iterator.hasNext()){
            iterator.next().update(); //更新所有Observer對象
        }

/*      也可采用增強for循環來周遊所有的Observer對象
 *      for(Observer observer:list){
            observer.update();
        }*/

    }

    //抽象方法(一定實作的操作)
    public abstract void operation();
}
           

實作AbstractSubscribe抽象類的抽象方法

package observer;

public class MySubscribe extends AbstractSubscribe{

    @Override
    public void operation() {
        // TODO 自動生成的方法存根
        System.out.println("update self!");
        notifyObservers();
    }
}
           

測試類(Test)

package observer;

/**
 * MySubscribe類就是我們的主對象,Observer1和Observer2是依賴于MySubscribe的對象,
 * 當MySubscribe變化時,這兩個對象必然變化。
 * AbstractSubscribe類中定義着需要監控的對象清單,可以對其進行修改:增加或删除被監控對象,
 * 當MySubscribe變化時,負責通知在清單記憶體在的對象
 * 
 * @author cx
 *
 */
public class Test {

    public static void main(String[] args) {
        Subscribe subscribe=new MySubscribe();

        subscribe.add(new Observer1());  //添加Observer對象  
        subscribe.add(new Observer2()); 

        subscribe.operation();  //subscribe 發出消息,所有Observer會做出響應
    }
}
           

測試結果

update self!
Observer1 has received!
Observer2 has received!
           

16.疊代子模式(Iterator)

簡單說明:這種模式用于順序通路集合對象的各個元素,而不需要知道集合對象的底層表示。

應用執行個體:JAVA中的iterator

舉例說明:

泛型接口

package iterator;

public interface MyIterable<T>{

    MyIterator<T> iterator();
}
           

疊代器接口

package iterator;

/**
 * 疊代器模式:
 * 意圖:提供一種方法順序通路一個聚合對象中各個元素,而又無需暴露該對象的内部表示
 *      這種模式用于順序通路集合對象中的元素,不需要知道集合對象的底層表示
 * 
 * 使用:周遊一個聚合對象
 * 優點:   1、它支援以不同的方式周遊一個聚合對象。
 *      2、疊代器簡化了聚合類。 3、在同一個聚合上可以有多個周遊。
 *      4、在疊代器模式中,增加新的聚合類和疊代器類都很友善,無須修改原有代碼。
         缺點:        由于疊代器模式将存儲資料和周遊資料的職責分離,增加新的聚合類需要對應增加新的疊代器類,
            類的個數成對增加,這在一定程度上增加了系統的複雜性。
 * @author cx
 *
 * @param <E>
 */

public interface MyIterator<E>{

    //前移
    public Object previous();

    //後移
    public Object next();

    //是否有下一個元素
    public boolean hasNext();

    //取得第一個元素
    public Object first();
}
           

自定義集合接口,這裡為了區分JAVA JDK中的集合類,特意取了别名MyColleation

package iterator;

public interface MyCollection<E> extends MyIterable<E>{

    //集合中寫一個未實作的方法(關于MyIterator疊代器的)
    public MyIterator<E> iterator();

    //取得集合元素
    public Object get(int i);

    //取得集合大小
    public int size();

    //添加集合元素
    public Object add(String string);

}
           

實作集合類中的操作

package iterator;

public class MyCollectionImpl<E> implements MyCollection<E>{

    private int size=;//預留數組大小,可以通過擴容數組來實作
    public String str[]=new String[size];

    private int i=;
    @Override
    public Object get(int i) {
        // TODO 自動生成的方法存根
        return str[i];
    }

    @Override
    public int size() {
        // TODO 自動生成的方法存根
        return str.length;
    }

    @Override
    public MyIterator<E> iterator() {
        // TODO 自動生成的方法存根
        return new MyIteratorImpl(this);
    }

    @Override
    public Object add(String string) {
        // TODO 自動生成的方法存根

        if(i<size){
            str[i]=string;
            i++;
        }else{
            String[] temp=new String[size];
            for(int j=;j<size;j++){
                temp[j]=str[j];
            }
            str=new String[size*];
            for(int j=;j<size;j++){
                str[j]=temp[j];
            }
            str[i]=string;
            i++;
        }

        return str;

    }

}
           

疊代器接口的實作類,同樣為了區分JAVA JDK 中的 Iterator接口名 特意取名MyIterator

package iterator;

public class MyIteratorImpl implements MyIterator{

    private MyCollection myCollection;
    private int pos=-;


    public MyIteratorImpl(MyCollection myCollection) {
        this.myCollection=myCollection;
    }

    @Override
    public Object previous() {
        //擷取上一個元素
        if(pos>){
            pos--;
        }
        return myCollection.get(pos);
    }

    @Override
    public Object next() {
        //擷取下一個元素
        if(pos<myCollection.size()-){
            pos++;
        }
        return myCollection.get(pos);
    }

    @Override
    public boolean hasNext() {
        //是否有下一個元素
        if(pos<myCollection.size()-){
            return true;
        }else{
            return false;
        }
    }

    @Override
    public Object first() {
        //傳回第一個元素
        pos=;
        return myCollection.get(pos);
    }

}
           

測試(Test)

package iterator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        MyCollectionImpl myCollectionImpl=new MyCollectionImpl();
        MyCollection<String> impl=new MyCollectionImpl<>();
        impl.add("1");
        impl.add("2");
        impl.add("3");
        impl.add("4");
        impl.add("5");
        impl.add("6");
        impl.add("7");
        impl.add("8");
        impl.add("9");
        impl.add("10");


        MyIterator<String> iterator2=impl.iterator();
        while(iterator2.hasNext()){
            System.out.print(" "+iterator2.next());
        }

    }
}
           

測試結果

1 2 3 4 5 6 7 8 9 10
           

17.責任鍊模式(ResponsibilityChain)

簡單說明:該模式為請求建立了一個接收者對象的鍊。這種模式給予請求的類型,對請求的發送者和接收者進行解耦。

意圖:避免請求發送者與接收者耦合在一起,讓多個對象都有可能接收請求,

将這些對象連接配接成一條鍊,并且沿着這條鍊傳遞請求,直到有對象處理它為止。

舉例說明:

package responsibilitychain;

public interface Handler {

    //操作
    public void operator();
}
           
package responsibilitychain;

public abstract class AbstractHandler {

    private Handler handler;

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

}
           
package responsibilitychain;

/**
 * 責任鍊模式:   有多個對象,每個對象持有對下一個對象的引用,這樣就會形成一條鍊,請求在這條鍊上傳遞
 *          直到某一對象決定處理該請求。但是發出者并不清楚到底最終那個對象會處理該請求,是以
 *          責任鍊模式可以實作。
 * 
 * 強調一點就是:連結上的請求可以是一條鍊,模式本身不限制這個,需要我們自己去實作。
 *          同時,在一個時刻,指令隻允許由一個對象傳給另一個對象,而不允許傳給多個對象。
 * @author cx
 *
 */

public class MyHandler extends AbstractHandler implements Handler{

    private String name;

    public MyHandler(String name) {
        this.name=name;
    }


    @Override
    public void operator() {
        System.out.println(name+"deal!");
        if(getHandler()!=null){
            getHandler().operator();      //遞歸調用operator()
        }
    }

}
           
package responsibilitychain;

public class Test {

    public static void main(String[] args) {
        MyHandler h1=new MyHandler("h1");
        MyHandler h2=new MyHandler("h2");
        MyHandler h3=new MyHandler("h3");

        h1.setHandler(h2);  //将h1對象和h2對象和h3對象進行關聯引用
        h2.setHandler(h3);  //鍊式調用
        h1.operator();      //操作将這些綁定在一條鍊中,一個一個調用
    }
}
           

測試結果

h1deal!
h2deal!
h3deal!
           

18.指令模式(Command)

簡單說明:請求以指令的形式包裹在對象中,并傳給調用對象。将一個請求封裝成一個對象,進而使你可以用不同的請求對客戶進行參數化。

舉例說明:

package command;

/**
 * 指令模式:很好了解,舉個例子,司令員下令讓士兵去幹件事情,從整個事情的角度來考慮,司令員的作用是,發出密碼,
 *           密碼經過傳遞,傳到了士兵耳朵裡,士兵去執行。三者互相解耦,任何一方都不用去依賴其他人,隻需要做好自己
 *         的事兒就行,司令員要的是結果,不會去關注到士兵去實作的。
 * 
 *  Invoker 是調用者(司令員),Receiver 是被調用者(士兵),MyCommand 是指令,持有接收對象
 * @author cx
 *
 * 指令模式的目的就是達到指令的發出者和執行者解耦,實作請求和執行分開,Struts其實就是一種将請求和呈現分離的技術
 */
public interface Command {

    //指令者釋出的指令類


    //執行這個指令的方法(交給接受者)
    public void exec();
}
           

接收者類(士兵)

package command;

/**
 * 接收指令者:(士兵)
 * @author cx
 *
 */
public class Receiver {

    public void action(){
        //接收指令的人執行指令的方法
        System.out.println("Command received!");
    }
}
           

指令類

package command;

//指令類
public class MyCommand implements Command{

    private Receiver receiver;

    public MyCommand(Receiver receiver) {
        this.receiver=receiver;
    }

    @Override
    public void exec() {
        //執行指令的方法
        //裡面的是執行指令的人的動作
        receiver.action();
    }

}
           

發出指令的司令員

package command;

//發出指令(司令員)
public class Invoker {

    private Command command;  //接口更好的擴充性

    public Invoker(Command command) {
        this.command=command;
    }

    public void action(){
        command.exec();  //發出指令
    }
}
           

測試(Test)

package command;

public class Test {

    public static void main(String[] args) {

        Receiver receiver=new Receiver();       //接收指令的士兵

        Command command=new MyCommand(receiver);//指令發給接收者

        Invoker invoker=new Invoker(command);   //司令員發出指令

        invoker.action();       //發出指令的類,指令類,接收指令的類,三者互相解耦
    }
}
           

測試結果

19.備忘錄模式(Memento)

簡單說明:儲存一個對象的某個狀态,以便在适當的時候恢複對象。在不破壞封裝性的前提下,捕獲一個對象的内部狀态,并在該對象之外儲存這個狀态。

舉例說明:

備忘錄類(Memento)

package memento;

/**
 * Memento (備忘錄模式):主要目的是儲存一個對象的某個狀态,以便在适當的時候恢複對象
 * 通俗來講:假設有原始類A,A中有各種屬性,A可以決定需要備份的屬性,備忘錄類B是用來存儲
 *        A的一些内部狀态,類C呢,就是一個用來存儲備忘錄的,且隻能存儲,不能修改等操作
 * @author cx
 * Memento 是備忘錄類
 */

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;
    }



}
           

原始類(需要儲存的Value)

package memento;

/**
 * Original 類是原始類,裡面有需要儲存的屬性Value及建立一個備忘錄類,用來儲存value值
 *
 * @author cx
 *
 */
public class Original {

    private String value;

    public Original(String value) {
        this.value=value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Memento createMemento(){
        //建立備忘錄,并儲存值在備忘錄中
        return new Memento(value);
    }

    public void restoreMemento(Memento memento){
        //還原備忘錄中儲存的值
        this.value=memento.getValue();
    }

}
           

Storage(存儲備忘錄的類)

package memento;

/**
 * Storage 是存儲備忘錄的類,持有Memento類的執行個體
 * @author cx
 * 就是用來存儲備忘錄的類
 */
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;
    }


}
           

測試(Test)

package memento;

public class Test {

    public static void main(String[] args) {

        //建立原始類
        Original original=new Original("egg");

        //建立備忘錄
        Storage storage=new Storage(original.createMemento());

        //修改原始類的狀态
        System.out.println("初始化狀态為:"+original.getValue());
        original.setValue("df");
        System.out.println("修改後的狀态為:"+original.getValue());

        //恢複原始類的狀态
        original.restoreMemento(storage.getMemento());
        System.out.println("恢複後的狀态為:"+original.getValue());

    }

}
           

測試結果

初始化狀态為:egg
修改後的狀态為:df
恢複後的狀态為:egg
           

20.狀态模式(State)

簡單說明:類的行為是基于它的狀态改變的。允許對象在内部狀态發生改變時改變它的行為,将各種具體的狀态抽象出來。

應用執行個體:打籃球的時候運動員可以有正常狀态、不正常狀态和超常狀态。

先寫一個State接口,内部隐藏一個Context 屬性

舉例說明:

package state;

public interface State {

    public void doAction(Context context);
}
           
package state;

public class Context {

    private State state;

    public Context() {
        state=null;  
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }


}
           

開始狀态StartState類,實作State接口

package state;

public class StartState implements State{

    @Override
    public void doAction(Context context) {
        // TODO 自動生成的方法存根
        System.out.println("Player is in start state");
        context.setState(this);  //記住一定要将state傳進來,不然會報空指針異常
    }

    @Override
    public String toString() {
        return "Start State";
    }
}
           

結束狀态類(StopState)實作State接口

package state;

public class StopState implements State{

    @Override
    public void doAction(Context context) {
        // TODO 自動生成的方法存根
        System.out.println("Player is in Stop State");
        context.setState(this);//記住一定要将state傳進來,不然會報空指針異常
    }

    @Override
    public String toString() {
        return "Stop State";
    }
}
           
package state;

public class Test {

    public static void main(String[] args) {
        Context context=new Context();

        StartState startState=new StartState();
        startState.doAction(context);

        System.out.println(context.getState().toString());

        StopState stopState=new StopState();
        stopState.doAction(context);

        System.out.println(context.getState().toString());
    }
}
           

測試結果

Player is in start state
Start State
Player is in Stop State
Stop State
           

21通路者模式(Visitor)

簡單說明:主要将資料結構與資料操作分離,它改變了元素類的執行算法,通過這種方式,元素的執行算法可以随着通路者改變而改變。

舉例說明:

package visitor;

/**
 * Visitor: 通路者模式把資料結構和作用于結構上的操作解耦合,使得操作集合可相對自由地演化。通路者模式适用于
 *          資料結構相對穩定算法又易變化的系統。因為通路者模式使得算法操作增加變得容易。
 *          若系統資料結構對象易于變化,經常有新的資料對象增加進來,則不适合使用通路者模式。
 * 優點:增加操作很容易,因為增加操作意味着增加新的通路者。通路者模式将有關行為集中到一個通路者對象中,其改變不影響系統
 *      資料結構。
 * 缺點:就是增加新的資料結構很困難。
 * 
 * @author cx
 * Visitor 存放要通路的對象
 */
public interface Visitor {

    public void visit(Subject sub);

}
           
package visitor;

public interface Subject {

    //accept方法,接受将要通路它的對象
    public void accept(Visitor visitor);

    //getSubject() 擷取将要被通路的屬性
    public String getSubject();
}
           
package visitor;

public class MyVisitor implements Visitor{

    //通路對象的方法
    @Override
    public void visit(Subject sub) {
        // TODO 自動生成的方法存根
        System.out.println("visit the subject:"+sub.getSubject());
    }


}
           
package visitor;

public class MySubject implements Subject{

    @Override
    public void accept(Visitor visitor) {
        // TODO 自動生成的方法存根
        visitor.visit(this);
    }

    @Override
    public String getSubject() {
        // TODO 自動生成的方法存根
        return "love";
    }

}
           
package visitor;

/**
 * 該模式适用場景:如果我們想為一個現有的類增加新功能,考慮這幾個事情
 *  1.新功能會不會與現有功能出現相容性的問題
 *  2.以後會不會再需要添加
 *  3.如果類不允許修改代碼怎麼辦
 *  通路者模式适用于資料結構相對穩定的系統,把資料結構和算法解耦
 * @author cx
 *
 */
public class Test {

    public static void main(String[] args) {
        Visitor visitor=new MyVisitor();

        Subject subject=new MySubject();

        subject.accept(visitor);
    }
}
           

測試結果

22.中介者模式

簡單說明:用一個中介對象來封裝一系列的對象互動,中

介者使各對象不需要顯示地互相引用,進而使耦合松散。

舉例說明:

package mediator;

/**
 * 中介者模式:也是用來降低類類之間的耦合的,因為如果類類之間有依賴關系的話,不利于功能的拓展和維護,因為隻要修改
 *          一個對象,其它關聯的對象都得進行修改。
 * 若使用中介者模式,隻需關心和Mediator類的關系,具體類類之間的關系及排程交給Mediator就行。
 * @author cx
 *
 */
public interface Mediator {

    public void createMediator();

    public void workAll();

}
           
package mediator;

/**
 * User類統一接口,User1和User2分别是不同的對象,二者之間有關聯,如果不采用中介者模式
 *         則需要二者互相持有引用,這樣二者的耦合度很高,為了解耦,引入Mediator類,提供統一接口
 *     MyMediator為其實作類,裡面持有User1和User2的執行個體,用來實作對User1和User2的控制
 *          這樣User1 和User2兩個對象互相獨立,他們隻需要保持好和Mediator之間的關系就行,剩下的全由
 *     MyMediator類來維護!
 * @author cx
 *
 */
public abstract class User {

    private Mediator mediator;

    public Mediator getMediator(){
        return mediator;
    }

    public User(Mediator mediator){
        this.mediator=mediator;
    }

    //抽象方法work()
    public abstract void work();
}
           
package mediator;

public class User1 extends User{

    public User1(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void work() {
        System.out.println("user1 exe!");
    }

}
           
package mediator;

public class User2 extends User{

    public User2(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void work() {
        System.out.println("user2 exe!");
    }

}
           
package mediator;

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();
    }

}
           
package mediator;

public class Test {

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

    }
}
           

測試結果

user1 exe!
user2 exe!
           

23.解釋器模式(Interpreter)

簡單說明:提供了評估語言的文法或表達式的方式。跟解釋器硬體有關,該模式用的比較少。

舉例說明:

package interpreter;

/**
 * 解釋器模式:一般應用在OOP開發的編譯器的開發中,是以适用面比較窄。
 * @author cx
 *
 */
public interface Expression {

    public int interpret(Context context);
}
           
package interpreter;

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;
    }

}
           
package interpreter;

public class Plus implements Expression{

    @Override
    public int interpret(Context context) {
        // TODO 自動生成的方法存根
        return context.getNum1()+context.getNum2();
    }

}
           
package interpreter;

public class Minus implements Expression{

    @Override
    public int interpret(Context context) {
        // TODO 自動生成的方法存根
        return context.getNum1()-context.getNum2();
    }

}
           
package interpreter;

public class Test {

    public static void main(String[] args) {
        int result=new Minus().
                interpret(new Context(new Plus().interpret(new Context(, )), ));
        System.out.println(result);
    }
}
           

測試結果

3
           

到這裡23種設計模式總算寫完了!!!

繼續閱讀