行爲型模式

整體分爲3大類:
建立型模式 (5種):工廠方法、抽象工廠、單例、建造者、原型
結構型模式(7種):適配器、裝飾器、代理、外觀、橋接、組合、享元
行爲型模式(11種):策略、模板方法、觀察者、迭代子、責任鏈、命令、備忘錄、狀態、訪問者、中介者、解釋器
其它(2種):併發型、線程池 正則表達式

先來看看這11種模式的關係:
第一類:經過父類與子類的關係進行實現。
第二類:兩個類之間。
第三類:類的狀態。
第四類:經過中間類算法

clipboard.png

1、父類與子類關係

策略(strategy)

定義一系列能夠相互替換的算法,並將每一個算法封裝起來。設計一個接口爲實現類提供統一的方法,設計一個抽象類(無關緊要,屬於輔助類)提供輔助函數:spring

clipboard.png

public interface ICalculator {
    int calculate(String exp);
}

輔助類:segmentfault

public abstract class AbstractCalculator {
    public int[] split(String exp, String opt){
        String array[] = exp.split(opt);
        int arrayInt[] = new int[2];
        arrayInt[0] = Integer.parseInt(array[0]);
        arrayInt[1] = Integer.parseInt(array[1]);
        return arrayInt;
    }
}

三個實現類:設計模式

public class Plus extends AbstractCalculator implements ICalculator {
    @Override
    public int calculate(String exp) {
        int arrayInt[] = split(exp,"\\+");
        return arrayInt[0]+arrayInt[1];
    }
}
public class Minus extends AbstractCalculator implements ICalculator {
    @Override
    public int calculate(String exp) {
        int arrayInt[] = split(exp,"-");
        return arrayInt[0]-arrayInt[1];
    }
}
public class Multiply extends AbstractCalculator implements ICalculator {
    @Override
    public int calculate(String exp) {
        int arrayInt[] = split(exp,"\\*");
        return arrayInt[0]*arrayInt[1];
    }
}

簡單的測試類:數據結構

public class StrategyTest {
    public static void main(String[] args) {
        String exp = "2+8";
        ICalculator cal = new Plus();
        int result = cal.calculate(exp);
        System.out.println(result);
    }
}

clipboard.png

策略模式多用在算法決策系統中,用戶只須要決定用哪一個算法便可。併發

模板方法(Template Method)

抽象類中有一個主方法,再定義n個方法(能夠是抽象的,也能夠是實際的方法),定義一個類繼承該抽象類,重寫抽象方法,經過調用抽象類,實現對子類的調用:
clipboard.png
就是在 AbstractCalculator 類中定義一個主方法 calculate,calculate()調用 spilt()等,Plus 和Minus 分別繼承 AbstractCalculator 類,經過對 AbstractCalculator 的調用實現對子類的調用:框架

public abstract class AbstractCalculator {

    /*主方法,實現對本類其它方法的調用*/
    public final int calculate(String exp, String opt){
        int array[] = split(exp,opt);
        return calculate(array[0],array[1]);
    }

    /*被子類重寫的方法*/
    protected abstract int calculate(int num1, int num2);

    private int[] split(String exp, String opt) {
        String[] array = exp.split(opt);
        int[] arrayInt = new int[2];
        arrayInt[0] = Integer.parseInt(array[0]);
        arrayInt[1] = Integer.parseInt(array[1]);
        return arrayInt;
    }
}
public class Plus extends AbstractCalculator {
    @Override
    protected int calculate(int num1, int num2) {
        return num1 + num2;
    }
}

測試類:數據結構和算法

public class StrategyTest {
    public static void main(String[] args) {
        String exp = "8+8";
        AbstractCalculator cal = new Plus();
        int result = cal.calculate(exp,"\\+");
        System.out.println(result);
    }
}

輸出:16ide

2、類之間關係

觀察者(Observer)

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

clipboard.png

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

public interface Observer {
    void update();
}

兩個實現類:

public class Observer1 implements Observer {
    @Override
    public void update() {
        System.out.println("observer1 has received!");
    }
}
public class Observer2 implements Observer{
    @Override
    public void update() {
        System.out.println("observer2 has received!");
    }
}

Subject 接口及實現類:

public interface Subject {
    /*增長觀察者*/
    void add(Observer observer);

    /*刪除觀察者*/
    void del(Observer observer);

    /*通知全部的觀察者*/
    void notifyObservers();

    /*自身的操做*/
    void operation();
}
public abstract class AbstractSubject implements Subject {
   private Vector<Observer> vector = new Vector<Observer>();

    @Override
    public void add(Observer observer) {
        vector.add(observer);
    }

    @Override
    public void del(Observer observer) {
        vector.remove(observer);
    }

    @Override
    public void notifyObservers() {
        Enumeration<Observer> enumo = vector.elements();
        while(enumo.hasMoreElements()){
            enumo.nextElement().update();
        }
    }
}
public class MySubject extends AbstractSubject {
    @Override
    public void operation() {
        System.out.println("update self!");
        notifyObservers();
    }
}

測試類:

public class ObserverTest {
    public static void main(String[] args) {
        MySubject sub = new MySubject();
        sub.add(new Observer1());
        sub.add(new Observer2());

        sub.operation();
    }
}

輸出:
update self!
observer1 has received!
observer2 has received!

迭代子(Iterator)

順序訪問集合中的對象,通常來講,集合中很是常見,若是對集合類比較熟悉的話,理解本模式會十分輕鬆。這句話包含兩層意思:一是須要遍歷的對象,即彙集對象,二是迭代器對象,用於對彙集對象進行遍歷訪問。咱們看下關係圖
圖片描述
這個思路和咱們經常使用的如出一轍,MyCollection 中定義了集合的一些操做,MyIterator 中定義了一系列迭代操做,且持有 Collection 實例,咱們來看看實現代碼:
兩個接口 :

public interface Collection {
    Iterator iterator();

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

    /*取得集合大小*/
    int size();
}
public interface Iterator {
    //前移
    Object previous();

    //後移
    Object next();
    boolean hasNext();

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

兩個實現:

public class MyCollection implements Collection {

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

    @Override
    public Iterator iterator() {
        return new MyIterator( this );
    }

    @Override
    public Object get(int i) {
        return string[i];
    }

    @Override
    public int size() {
        return string.length;
    }
}
public class MyIterator implements Iterator {
    private Collection collection;
    private int pos = -1;

    public MyIterator(Collection collection) {
        this.collection = collection;
    }

    @Override
    public Object previous() {
        if (pos > 0) {
            pos--;
        }
        return collection.get(pos);
    }

    @Override
    public Object next() {
        if (pos < collection.size() - 1) {
            pos++;
        }
        return collection.get(pos);
    }

    @Override
    public boolean hasNext() {
        if (pos < collection.size() - 1) {
            return true;
        }else {
            return false;
        }
    }

    @Override
    public Object first() {
        pos = 0;
        return collection.get(pos);
    }
}

測試類:

public class Test {
    public static void main(String[] args) {
        MyCollection collection = new MyCollection();
        Iterator it = collection.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

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

責任鏈(Chain of Responsibility)

接下來咱們將要談談責任鏈模式,有多個對象,每一個對象持有對下一個對象的引用,這樣就會造成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。可是發出者並不清楚到底最終那個對象會處理該請求,因此,責任鏈模式能夠實現,在隱瞞客戶端的狀況下,對系統進行動態的調整。先看看關係圖:
圖片描述
Abstracthandler 類提供了 get 和 set 方法,方便 MyHandle 類設置和修改引用對象,MyHandle類是核心,實例化後生成一系列相互持有的對象,構成一條鏈 。

public interface Handler {
    void operator();
}
public abstract class AbstractHandler {
    private Handler handler;

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }
}
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 (null != getHandler()) {
            getHandler().operator();
        }
    }
}
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);
        h2.setHandler(h3);
        h1.operator();
    }
}

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

命令(Command)

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

public interface Command {
    void exe();
}
public class MyCommand implements Command {
    private Receiver receiver;

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

    @Override
    public void exe() {
        receiver.action();
    }
}
public class Receiver {
    public void action() {
        System.out.println("command received!");
    }
}
public class Invoker {
    private Command command;

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

    public void action() {
        command.exe();
    }
}
public class Test {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        MyCommand cmd = new MyCommand(receiver);
        Invoker invoker = new Invoker(cmd);
        invoker.action();
    }
}

輸出:command received!
命令模式的目的就是達到命令的發出者和執行者之間解耦,實現請求和執行分開,熟悉 Struts 的同窗應該知道,Struts 其實就是一種將請求和呈現分離的技術,其中必然涉及命令模式的思想!
其實每一個設計模式都是很重要的一種思想,看上去很熟,實際上是由於咱們在學到的東西中都有涉及,儘管有時咱們並不知道,其實在 Java 自己的設計之中到處都有體現,像 AWT、JDBC、集合類、IO 管道或者是 Web 框架,裏面設計模式無處不在。由於咱們篇幅有限,很難講每個設計模式都講的很詳細,不過我會盡我所能,儘可能在有限的空間和篇幅內,把意思寫清楚了,更好讓你們明白。

3、類的狀態

備忘錄(Memento)

主要目的是保存一個對象的某個狀態,以便在適當的時候恢復對象,我的以爲叫備份模式更形象些,通俗的講下:假設有原始類 A,A 中有各類屬性,A 能夠決定須要備份的屬性,備忘錄類 B 是用來存儲 A 的一些內部狀態,類 C 呢,就是一個用來存儲備忘錄的,且只能存儲,不能修改等操做。作個圖來分析一下:
圖片描述
Original 類是原始類,裏面有須要保存的屬性 value 及建立一個備忘錄類,用來保存 value 值。Memento 類是備忘錄類,Storage 類是存儲備忘錄的類,持有 Memento 類的實例,該模式很好理解。直接看源碼:

public class Original {
    private String 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 String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
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,最後倒數第二行進行恢復狀態,結果成功恢復了。其實我以爲這個模式叫「備份-恢復」模式最形象。

狀態(State)

核心思想就是:當對象的狀態改變時,同時改變其行爲,很好理解!就拿 QQ 來講,有幾種狀態,在線、隱身、忙碌等,每一個狀態對應不一樣的操做,並且你的好友也能看到你的狀態,因此,狀態模式就兩點:一、能夠經過改變狀態來得到不一樣的行爲。二、你的好友能同時看到你的變化。看圖:
圖片描述

public class State {
    private String value;

    public void method1() {
        System.out.println("execute the first opt!");
    }

    public void method2() {
        System.out.println("execute the second opt!");
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
public class Context {
    private State state;

    public void method() {
        if (state.getValue().equals("state1")) {
            state.method1();
        } else if (state.getValue().equals("state2")) {
            state.method2();
        }
    }

    public Context(State state) {
        this.state = state;
    }

    public State getState() {
        return state;
    }

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

測試類:

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!
根據這個特性,狀態模式在平常開發中用的挺多的,尤爲是作網站的時候,咱們有時但願根據對象的某一屬性,區別開他們的一些功能,好比說簡單的權限控制等 。

4、經過中間類

訪問者(Visitor)

訪問者模式把數據結構和做用於結構上的操做解耦合,使得操做集合可相對自由地演化。訪問者模式適用於數據結構相對穩定算法又易變化的系統。由於訪問者模式使得算法操做增長變得容易。若系統數據結構對象易於變化,常常有新的數據對象增長進來,則不適合使用訪問者模式。訪問者模式的優勢是增長操做很容易,由於增長操做意味着增長新的訪問者。訪問者模式將有關行爲集中到一個訪問者對象中,其改變不影響系統數據結構。其缺點就是增長新的數據結構很困難。—— From 百科
簡單來講,訪問者模式就是一種分離對象數據結構與行爲的方法,經過這種分離,可達到爲一個被訪問者動態添加新的操做而無需作其它的修改的效果。簡單關係圖:
圖片描述

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

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

public interface Subject {
    void accept(Visitor visitor);
    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
該模式適用場景:若是咱們想爲一個現有的類增長新功能,不得不考慮幾個事情:一、新功能會不會與現有功能出現兼容性問題?二、之後會不會再須要添加?三、若是類不容許修改代碼怎麼辦?面對這些問題,最好的解決方法就是使用訪問者模式,訪問者模式適用於數據結構相對穩定的系統,把數據結構和算法解耦,

中介者(Mediator)

中介者模式也是用來下降類類之間的耦合的,由於若是類類之間有依賴關係的話,不利於功能的拓展和維護,由於只要修改一個對象,其它關聯的對象都得進行修改。若是使用中介者模式,只需關心和 Mediator 類的關係,具體類類之間的關係及調度交給 Mediator 就行,這有點像spring 容器的做用。先看看圖:
圖片描述
User 類統一接口,User1 和 User2 分別是不一樣的對象,兩者之間有關聯,若是不採用中介者模式,則須要兩者相互持有引用,這樣兩者的耦合度很高,爲了解耦,引入了 Mediator 類,提供統一接口,MyMediator 爲其實現類,裏面持有 User1 和 User2 的實例,用來實現對 User1和 User2 的控制。這樣 User1 和 User2 兩個對象相互獨立,他們只須要保持好和 Mediator 之間的關係就行,剩下的全由 MyMediator 類來維護!基本實現:

public interface Mediator {
    void createMediator();
    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 abstract void work();

    public Mediator getMediator() {
        return mediator;
    }

    public User(Mediator mediator) {
        this.mediator = mediator;
    }
}
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) {
        MyMediator mediator = new MyMediator();
        mediator.createMediator();
        mediator.workAll();
    }
}

輸出:
user1 exe!
user2 exe!

解釋器(Interpreter)

解釋器模式是咱們暫時的最後一講,通常主要應用在 OOP 開發中的編譯器的開發中,因此適用面比較窄。
圖片描述
Context 類是一個上下文環境類,Plus 和 Minus 分別是用來計算的實現,代碼以下:

public interface Expression {
    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。基本就這樣,解釋器模式用來作各類各樣的解釋器,如正則表達式等的解釋器等等!

相關文章
相關標籤/搜索