設計模式--簡化解釋(三)——行爲型模式

1.建立型設計模式
2.結構型設計模式
3.行爲型設計模式java

行爲型設計模式

簡而言之android

行爲型設計模式關心的是對象之間的責任分配。它們與結構模式的不一樣之處在於,它們不只指定告終構,並且還概述了它們之間消息傳遞/通訊的模式。換句話說,他們幫助回答「在軟件組件中如何管理一個行爲?」

維基百科說ios

在軟件工程中,行爲設計模式是一種設計模式,用於識別對象之間的公共通訊模式並實現這些模式. 這樣作,這些設計模式在傳遞信息的時候增長了靈活性。

? 職責鏈模式

顯示舉例算法

例如,在你的帳戶中有三種支付方式( A, B, C),每個都有不一樣的金額的錢。 A中有100美圓, B中有300美圓, C中有1000美圓。選擇支付方式的偏好爲 A, BC.你嘗試購買價值210美圓的商品。使用職責鏈,首先檢查 A可否支持購買,若是能夠則進行購買,職責終端。不然,請求轉發到帳戶 B,若是職責中斷,則請求一致轉發直到找到符合條件的處理器。在這裏, A, B, C是鏈式鏈接,整個現象就是職責鏈。

簡而言之編程

職責鏈模式幫助構建一個對象鏈。請求從一個端點進入,一直從一個對象到另外一個對象,直到找到合適的處理器。

維基百科說segmentfault

在面向對象的設計中,責任鏈模式是由一個命令對象的源和一系列處理對象組成的設計模式。 每一個處理對象都包含定義它能夠處理的命令對象類型的邏輯;其他的被傳遞給鏈中的下一個處理對象。

編程示例設計模式

翻譯咱們上面的賬戶示例。首先,咱們有一個基本賬戶,它有把賬戶合併在一塊兒的邏輯,和一些其餘賬戶。服務器

public abstract class Account {
    protected float balance;
    private Account successor;

    public Account(float balance) {
        this.balance = balance;
    }

    public void setNext(Account account)
    {
        this.successor = account;
    }

    public void pay(float amount)
    {
        if(canPay(amount))
        {
            System.out.println(String.format("Can pay $%s use %s",amount,this.getClass().getSimpleName()));
        }
        else
        {
            System.out.println(String.format("Can not pay,forwarding:%s",successor.getClass().getSimpleName()));
            successor.pay(amount);
        }
    }

    public boolean canPay(float amount)
    {
        return Float.compare(balance,amount) > 0;
    }
}
public class Bank extends Account {
    public Bank(float balance) {
        super(balance);
    }
}
public class Paypal extends Account {
    public Paypal(float balance) {
        super(balance);
    }
}
public class Bitcoin extends Account{
    public Bitcoin(float balance) {
        super(balance);
    }
}

如今咱們使用上邊準備的鏈式鏈接。網絡

// 咱們準備的支付鏈以下
//      bank->paypal->bitcoin
//
// 首選bank
//  若是 bank不能支付選擇 paypal
//  若是 paypal不能支付選擇 bit coin

Account bank = new Bank(100);
Account paypay = new Paypal(200);
Account bitcon = new Bitcoin(300);

bank.setNext(paypay);
paypay.setNext(bitcon);

bank.pay(259);

? 命令模式

現實舉例app

一個典型的例子就是你在餐館點餐。你(「客戶端」)問服務員(調用者,「Invoker」)帶一些食物(「命令」,Command),服務員簡單地將請求轉發給廚師,這個廚師是懂得如何烹飪的人。
另外一個例子是你(客戶端,"Client")使用遙控(調用者,"Invoke")切換電視節目(命令,"Command")。
簡而言之
容許您封裝對象中的操做。此模式背後的關鍵思想是提供將客戶端與接收方解耦合的方法。

維基百科說

在面向對象的編程中,命令模式是一種行爲設計模式,在該模式中,對象被用來封裝執行某個動做所需的全部信息,或者在稍後的時間觸發事件。該信息包括方法名稱、擁有方法參數的對象以及方法參數的值。

編程示例

首先,咱們有一個接收器,它能夠執行全部能夠執行的動做。

// Receiver(接收者)
public class Bulb {
    public void turnOn()
    {
        System.out.println("Bulb has been lit");
    }

    public void turnOff()
    {
        System.out.println("Darkness");
    }
}

而後咱們有一個接口,每一個命令都要實現,另外咱們有一組命令。

public interface Command {
    void undo();
    void redo();
    void execute();
}
// Command
public class TurnOffCommand implements Command {
    private Bulb bulb;

    public TurnOffCommand(Bulb bulb) {
        this.bulb = bulb;
    }

    @Override
    public void undo() {
     this.bulb.turnOn();
    }

    @Override
    public void redo() {
        this.bulb.turnOff();
    }

    @Override
    public void execute() {
        this.bulb.turnOff();
    }
}
public class TurnOnCommand implements Command {
    private Bulb bulb;

    public TurnOnCommand(Bulb bulb) {
        this.bulb = bulb;
    }

    @Override
    public void undo() {
        this.bulb.turnOff();
    }

    @Override
    public void redo() {
        this.bulb.turnOn();
    }

    @Override
    public void execute() {
        this.bulb.turnOn();
    }
}

接着咱們有調用者(Invoker),客戶端可使用調用者來處理任意的命令

// 調用者
public class RemoteControl {
    public void submit(Command command)
    {
        command.execute();
    }
}

最後看一下客戶端如何使用

Bulb bulb = new Bulb();

Command turnOnCommand = new TurnOnCommand(bulb);
Command turnOffCommand = new TurnOffCommand(bulb);

RemoteControl remoteControl = new RemoteControl();
remoteControl.submit(turnOnCommand);

remoteControl.submit(turnOnCommand);

命令模式還能夠用於實現基於事務的系統。當您執行命令的歷史時,您將保持它的歷史。若是最終的命令被成功執行,那麼全部的好方法都只是遍歷歷史,並在全部執行的命令上執行「撤消」。

➿ 迭代器模式

現實舉例

一臺舊的收音機將會是一個很好的迭代器的例子,用戶能夠從某個頻道開始,而後使用下一個或以前的按鈕來瀏覽各個頻道。 或者舉一個MP3播放器或電視機的例子,你能夠按下一個和以前的按鈕,經過連續的頻道。換句話說,它們都提供一個接口,經過各自的頻道、歌曲或廣播電臺進行迭代。

簡而言之

它提供了一種方法來訪問對象的元素,而不暴露底層的表示。

維基百科說

在面向對象編程中,迭代器模式是一種設計模式,其中迭代器用於遍歷容器並訪問容器的元素。 迭代器模式將算法從容器中分離出來;在某些狀況下,算法必須是特定於容器的,所以不能解耦。

編程舉例

在Java中能夠結合Iterator接口來實現迭代器模式。翻譯上邊收音機的例子以下;

public class RadioStation {
    private float frequency;

    public RadioStation(float frequency) {
        this.frequency = frequency;
    }

    public float getFrequency() {
        return frequency;
    }
}

咱們有咱們本身的迭代器

public class StationList implements Iterator<RadioStation> {

    private List<RadioStation> stations = new ArrayList<>();
    private int counter = 0;

    @Override
    public boolean hasNext() {
        return counter < stations.size();
    }

    @Override
    public RadioStation next() {
        return stations.get(counter++);
    }

    public void add(RadioStation radioStation)
    {
        stations.add(radioStation);
    }

    public RadioStation remove(RadioStation radioStation)
    {
        for(int i = 0; i < stations.size(); i++)
        {
            if(Float.compare(stations.get(i).getFrequency(),radioStation.getFrequency())==0)
            {
                return  stations.remove(i);
            }
        }

        return null;
    }

    public int count()
    {
        return stations.size();
    }

    public RadioStation current()
    {
        return stations.get(counter);
    }

    public int key()
    {
        return counter;
    }

    public void rewind()
    {
        counter=0;
    }

}

使用方式以下

StationList stationList = new StationList();
stationList.add(new RadioStation(120.1F));
stationList.add(new RadioStation(99.1F));
stationList.add(new RadioStation(156.7F));
stationList.add(new RadioStation(138.2F));
stationList.add(new RadioStation(89.6F));
stationList.add(new RadioStation(78.9F));

while(stationList.hasNext())
{
    System.out.println(stationList.next().getFrequency());
}

? 中介模式

現實舉例

一個普通的例子是當你和某人在你的移動電話上交談時,你和他們之間有一個網絡供應商,你的談話經過它而不是直接發送。在這種狀況下,網絡供應商是中介。

簡而言之

中介模式添加第三方對象(稱爲中介)來控制兩個對象之間的交互(稱爲同事)。它有助於減小相互通訊的類之間的耦合。由於如今他們不須要知道彼此的實現。

維基百科說

在軟件工程中,中介模式定義了一個對象,它封裝了一組對象如何交互。這種模式被認爲是一種行爲模式,由於它能夠改變程序的運行行爲。

編程示例

這裏是一個與用戶相互發送消息的聊天室最簡單的例子。

首先咱們有中介,也就是聊天室。

public interface ChatRoomMediator {
    void showMessage(User user,String message);
}
// Mediator
public class ChatRoom implements ChatRoomMediator {
    private SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public void showMessage(User user, String message) {
        String date = sf.format(Calendar.getInstance().getTime());
        System.out.println(String.format("%s [%s] says:%s",date,user.getUserName(),message));
    }
}

下面是咱們的用戶

public class User {
    private String userName;
    private ChatRoomMediator chatRoomMediator;

    public User(String userName, ChatRoomMediator chatRoomMediator) {
        this.userName = userName;
        this.chatRoomMediator = chatRoomMediator;
    }

    public String getUserName() {
        return userName;
    }

    public void sendMessage(String message)
    {
        this.chatRoomMediator.showMessage(this,message);
    }
}

使用以下

ChatRoomMediator mediator = new ChatRoom();
User john = new User("John",mediator);
User jane = new User("Jane",mediator);

john.sendMessage("Hi there!");
jane.sendMessage("Hey!");

? 備忘錄模式

現實舉例

以計算器爲例,當您執行某些計算時,最後的計算將保存在內存中,這樣您就能夠返回到它,並使用一些操做按鈕(即管理員)恢復它。

簡而言之

Memento模式是關於捕獲和存儲對象的當前狀態的方式,它能夠在稍後以一種平滑的方式恢復。

維基百科說

memento模式是一種軟件設計模式,它提供了將對象恢復到之前狀態的能力(經過回滾撤銷)。

一般在須要提供某種撤銷功能時很是有用。

編程示例

讓咱們舉一個文本編輯器的例子,它能夠隨時保存狀態,若是須要,能夠恢復。

首先,咱們有一個能夠保存編輯器狀態的memento對象。

public class EditorMemento {
    private String content;

    public EditorMemento(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}

界限來咱們有一個編輯器來使用memento對象

public class Editor {
    private String content="";

    public void type(String words)
    {
       content = String.format("%s %s",content,words);
    }

    public EditorMemento save()
    {
        return new EditorMemento(content);
    }

    public void resotre(EditorMemento memento)
    {
        this.content = memento.getContent();
    }

    public String getContent() {
        return content;
    }
}

使用方式以下

Editor editor = new Editor();
editor.type("This is the first sentence.");
editor.type("This is second.");

EditorMemento memento = editor.save();
editor.type("And this is third.");
editor.resotre(memento);

System.out.println(editor.getContent());

? 觀察者模式

現實舉例

一個很好的例子就是求職者在招聘網站時,只要有匹配的工做機會,他們就會獲得通知。

簡而言之

定義對象之間的依賴關係,以便每當對象更改其狀態時,都會通知全部依賴對象。

維基百科說

觀察者模式是一種軟件設計模式,其中一個對象被稱爲主題,它維護一個被稱爲觀察者的依賴項列表,並經過調用其中一個方法來自動通知它們任何狀態變化。

編程示例
翻譯咱們上邊的例子。首先咱們有須要被通知招聘職位的求職者。

注:JDK中提供了Observer接口和Observal抽象類來實現觀察者模式
public class JobPost {
    public String title;

    public JobPost(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }
}
public class JobSeeker implements Observer {
    private String name;

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

    @Override
    public void update(Observable o, Object arg) {
        JobPost jobPost = (JobPost)arg;

        System.out.println(String.format("Hi,%s!New Job posted:%s",name,jobPost.getTitle()));
    }
}

而後,咱們會有招聘人員會訂閱的招聘信息。

public class JobPostings extends java.util.Observable {

    private void notity(JobPost jobPost)
    {
        super.setChanged();
        notifyObservers(jobPost);
    }

    public void addJob(JobPost jobPost)
    {
        notity(jobPost);
    }
}

使用方式以下

JobSeeker john = new JobSeeker("John");
JobSeeker jane = new JobSeeker("Jane");

JobPostings jobPostings = new JobPostings();
jobPostings.addObserver(john);
jobPostings.addObserver(jane);

jobPostings.addJob(new JobPost("Java Developer"));

? 訪問者模式

現實舉例

考慮某人去迪拜。 他們只是須要一種方式(即簽證)進入迪拜。抵達後,他們能夠自行前往迪拜的任何地方,而無需事先徵得許可或作一些跑腿的工做,以便參觀任何地方,只要讓他們知道一個地方,他們就能夠去參觀。 訪問者模式容許你這樣作,它能夠幫助你添加訪問的地方,這樣他們就能夠儘量多地訪問,而沒必要作任何跑腿的工做。

簡而言之

訪問者模式容許您在不修改對象的狀況下爲對象添加更多操做。

維基百科說

在面向對象編程和軟件工程中,訪問者設計模式是一種將算法從其操做的對象結構中分離出來的方法。這種分離的實際結果是,在不修改這些結構的狀況下,能夠向現有的對象結構添加新的操做。這是遵循開放/封閉原則的一種方法。

編程示例

讓咱們舉一個動物園模擬的例子,咱們有幾種不一樣種類的動物,咱們必須讓它們發聲。 咱們使用訪問者模式來翻譯一下這個例子。

// Visitee
public interface Animal {
    void accept(AnimalOperation operation);
}

// Visitor
public interface AnimalOperation {
    void visitMonkey(Monkey monkey);
    void visitLoin(Lion lion);
    void visitDolphin(Dolphin dolphin);
}

動物的實現

public class Monkey implements Animal {
    public void shout()
    {
        System.out.println("Ooh oo aa aa!");
    }

    @Override
    public void accept(AnimalOperation operation) {
        operation.visitMonkey(this);
    }
}
public class Dolphin implements Animal {
    public void speak()
    {
        System.out.println("Tuut tuttu tuutt!");
    }

    @Override
    public void accept(AnimalOperation operation) {
        operation.visitDolphin(this);
    }
}
public class Lion implements Animal {
    public void roar()
    {
        System.out.println("Roaaar");
    }

    @Override
    public void accept(AnimalOperation operation) {
        operation.visitLoin(this);
    }
}

訪問者

public class Speak implements AnimalOperation {
    @Override
    public void visitMonkey(Monkey monkey) {
        monkey.shout();
    }

    @Override
    public void visitLoin(Lion lion) {
        lion.roar();
    }

    @Override
    public void visitDolphin(Dolphin dolphin) {
        dolphin.speak();
    }
}

使用方式以下

Monkey monkey = new Monkey();
        Lion lion = new Lion();
        Dolphin dolphin = new Dolphin();

        Speak speak = new Speak();

        monkey.accept(speak);
        lion.accept(speak);
        dolphin.accept(speak);

咱們本能夠簡單地爲動物創建一個繼承等級,但若是咱們須要向動物添加新動做,咱們就必須修改動物。但如今咱們不須要改變它們。例如,假設咱們被要求將跳轉行爲添加到動物中,咱們能夠簡單地經過建立一個新的訪問者來添加該行爲。

public class Jump implements AnimalOperation {
    @Override
    public void visitMonkey(Monkey monkey) {
        System.out.println("Jumped 20 feet high! on to the tree!");
    }

    @Override
    public void visitLoin(Lion lion) {
        System.out.println("Jumped 7 feet! Back on the ground!");
    }

    @Override
    public void visitDolphin(Dolphin dolphin) {
        System.out.println("Walked on water a little and disappeared");
    }
}

使用以下

Monkey monkey = new Monkey();
Lion lion = new Lion();
Dolphin dolphin = new Dolphin();

Speak speak = new Speak();

monkey.accept(speak);
lion.accept(speak);
dolphin.accept(speak);
System.out.println("=======================");

AnimalOperation jump = new Jump();
monkey.accept(jump);
lion.accept(jump);
dolphin.accept(jump);

? 策略模式

現實舉例

考慮一下排序的例子,咱們實現了冒泡排序,但數據開始增加,而冒泡排序開始變得很是緩慢。爲了解決這個問題,咱們實現了快速排序。可是如今,儘管快速排序算法在大型數據集上作得更好,可是對於較小的數據集來講,它是很是慢的。爲了處理這個問題,咱們實現了一個策略,在這個策略中,小數據集,冒泡排序將被使用,並用於更大的,快速排序。

簡而言之

策略模式容許您根據狀況切換算法或策略。策略模式容許您根據狀況切換算法或策略。

維基百科說

在計算機編程中,策略模式(也稱爲策略模式)是一種行爲軟件設計模式,它容許在運行時選擇算法的行爲。

編程示例

翻譯咱們上面的例子。首先,咱們有策略接口和不一樣的策略實現。

public interface SortStrategy {
    int[] sort(int[] arr);
}
public class BubbleSortStrategy implements SortStrategy {
    @Override
    public int[] sort(int[] arr) {
        System.out.println("Sorting using bubble sort");

        return arr;
    }
}
public class QuickSortStrategy implements SortStrategy{
    @Override
    public int[] sort(int[] arr) {
        System.out.println("Sorting using quick sort");
        return arr;
    }
}

咱們的客戶端可使用任何策略。

public class Sorter {
    private SortStrategy sortStrategy;

    public Sorter(SortStrategy sortStrategy) {
        this.sortStrategy = sortStrategy;
    }

    public int[] sort(int[] arr)
    {
        return sortStrategy.sort(arr);
    }
}

使用方式以下

int[] arr = {1, 5, 4, 3, 2, 8};

Sorter sorter = new Sorter(new BubbleSortStrategy());
sorter.sort(arr);
System.out.println("=========================");
sorter = new Sorter(new QuickSortStrategy());
sorter.sort(arr);

? 狀態模式

現實舉例

假設您正在使用一些繪圖應用程序,您選擇畫筆繪製。如今畫筆會根據所選的顏色改變它的行爲若是你選擇了紅色,它會畫出紅色,若是藍色,它會是藍色的等等。

簡而言之

它容許在狀態更改時更改類的行爲。

維基百科說

狀態模式是一種行爲軟件設計模式,它以面向對象的方式實現狀態機。 在狀態模式下,狀態機經過實現每一個單個狀態做爲狀態模式接口的派生類實現,並經過調用模式父類定義的方法實現狀態轉換。
狀態模式能夠解釋爲一種策略模式,它能夠經過在模式接口中定義的方法調用來切換當前策略。

編程示例

讓咱們舉一個文本編輯器的例子,它容許你改變輸入的文本的狀態,若是你選擇了粗體,它開始以粗體輸入;若是選擇斜體,以斜體輸入,等等。

首先咱們有狀態接口和狀態的實現。

public interface WriteState {
    void write(String word);
}
public class UpperState implements WriteState {
    @Override
    public void write(String word) {
        System.out.println(word.toUpperCase());
    }
}
public class LowerState implements WriteState {
    @Override
    public void write(String word) {
        System.out.println(word.toLowerCase());
    }
}
public class DefaultState implements WriteState {
    @Override
    public void write(String word) {
        System.out.println(word);
    }
}

而後咱們有一個編輯器

public class TextEditor {
    private WriteState writeState;

    public TextEditor(WriteState writeState) {
        this.writeState = writeState;
    }

    public void setWriteState(WriteState writeState) {
        this.writeState = writeState;
    }

    public void type(String word)
    {
        this.writeState.write(word);
    }
}

使用方式以下

TextEditor editor = new TextEditor(new DefaultState());
editor.type("First line");

editor.setWriteState(new LowerState());
editor.type("Second line");
editor.type("Third line");

editor.setWriteState(new UpperState());
editor.type("Forth line");
editor.type("Fifth line");

? 模版方法模式

現實舉例

假設咱們要建一些房子。建造的步驟多是這樣的。

  • 打地基
  • 建牆
  • 增長房頂
  • 增長其餘的樓層

這些步驟的順序是不可能改變的,例如,在建造牆以前你不能建造屋頂,可是每個步驟均可以被修改,例如牆壁能夠用木頭或聚酯或石頭作。

簡而言之

模板方法定義瞭如何執行某個算法的骨架,但將這些步驟的實現轉移到子類中。

維基百科說

在軟件工程中,模板方法模式是一種行爲設計模式,它在操做中定義算法的程序骨架,將一些步驟推遲到子類。它讓一我的從新定義算法的某些步驟而不改變算法的結構。

Programmatic Example

假設咱們有一個構建工具,它能夠幫助咱們測試、lint、構建、生成構建報告(好比代碼覆蓋率報告、linting報告等),並在測試服務器上部署咱們的應用程序。

首先,咱們有一個爲構建算法指定骨架的基類。

public abstract class Builder {

    public void build() {
        test();
        lint();
        assemble();
        deploy();
    }

    public abstract void test();

    public abstract void lint();

    public abstract void assemble();

    public abstract void deploy();
}

實現

public class AndroidBuilder extends Builder {
    @Override
    public void test() {
        System.out.println("Running android tests");
    }

    @Override
    public void lint() {
        System.out.println("Linting the android code");
    }

    @Override
    public void assemble() {
        System.out.println("Assembling the android build");
    }

    @Override
    public void deploy() {
        System.out.println("Deploying android build to server");
    }
}
public class IOSBuilder extends Builder {
    @Override
    public void test() {
        System.out.println("Running ios tests");
    }

    @Override
    public void lint() {
        System.out.println("Linting the ios code");
    }

    @Override
    public void assemble() {
        System.out.println("Assembling the ios build");
    }

    @Override
    public void deploy() {
        System.out.println("Deploying ios build to server");
    }
}

使用以下

Builder builder = new AndroidBuilder();
builder.build();
System.out.println("========================");
builder = new IOSBuilder();
builder.build();
相關文章
相關標籤/搜索