1. 程式人生 > >設計模式-行為型模式

設計模式-行為型模式

行為型模式

  • 模版方法模式
  • 策略模式
  • 狀態模式
  • 命令模式
  • 迭代器模式
  • 備忘錄模式
  • 觀察者模式
  • 中介者模式
  • 訪問者模式
  • 責任鏈模式
  • 直譯器模式

模版方法模式

定義:定義一個操作中演算法的框架,而將一些步驟延遲到子類中,使得子類可以不改變演算法的結構即可重定義該演算法中的某些特定步驟。

這裡寫圖片描述

模版模式的核心是一個抽象類。抽象類將實現邏輯的骨架定義好,具體實現的抽象方法有繼承的子類去實現。

策略模式

定義:定義一組演算法,將每個演算法都封裝起來,並且使他們之間可以互換。

這裡寫圖片描述

策略模式與模版模式的區別在於:
在模版方法模式中,呼叫演算法的主體在抽象的父類中,而在策略模式中,呼叫演算法的主體則是封裝到了封裝類Context中。

狀態模式

定義:狀態模式允許一個物件在其內部狀態改變的時候改變其行為。這個物件看上去就像是改變了它的類一樣。

這裡寫圖片描述

簡單地說:一個Context物件的狀態會發生改變,在他狀態傳送改變後,若呼叫request方法,具體的操作是有目前狀態的handle方法來操作的,就如同request方法的發生了變化,換種說法,就如同Context物件看上去是改變了類。

狀態模式與策略模式有相似之處,都是把具體的處理邏輯抽象封裝出來,區別在於:
狀態模式將各個狀態所對應的操作分離開來,即對於不同的狀態,由不同的子類實現具體操作,不同狀態的切換由子類實現,當發現傳入引數不是自己這個狀態所對應的引數,則自己給Context類切換狀態

;而策略模式是直接依賴注入到Context類的引數進行選擇策略,不存在切換狀態的操作。

命令模式

定義:將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。

這裡寫圖片描述

命令模式的核心在於對命令的封裝,即通過將對命令的操作(接受者介面方法的執行順序等)封裝在命令物件的方法中,然後在合適的時間由呼叫者物件進行呼叫。呼叫者Invoker持有一組命令物件的例項。

通過命令物件可以有效降低命令與呼叫者對於具體操作的耦合,同時可以實現命令的撤銷,批量執行等操作。

缺點:過多的簡單命令物件建立(幾行程式碼)會造成封裝的繁瑣。

迭代器模式

定義:提供一種方法訪問一個容器物件中各個元素,而又不暴露該物件的內部細節。

這裡寫圖片描述

迭代器與集合是密不可分的,它可以在隱藏集合物件的內部實現的情況下提供一種有效的遍歷集合的方式。

備忘錄模式

定義:在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣就可以將該物件恢復到原先儲存的狀態。

這裡寫圖片描述

發起人物件的某一瞬時狀態可以用備忘錄物件儲存(可以是發起人物件的全部或部分屬性值),備忘錄有管理角色管理(管理角色儲存一組備忘錄物件的例項)。在需要還原的時候,可以通過獲取管理角色中所保管的備忘錄物件來還原發起人的狀態。

觀察者模式

定義:定義物件間一種一對多的依賴關係,使得當每一個物件改變狀態,則所有依賴於它的物件都會得到通知並自動更新。

這裡寫圖片描述

如果一個物件的狀態發生改變,某些與它相關的物件也要隨之做出相應的變化,這時候最佳的解決方案既是觀察者模式。

觀察者模式一個重要點是註冊於被觀察者中的觀察者集合。

中介者模式

定義:用一箇中介者物件封裝一系列的物件互動,中介者使各物件不需要顯示地相互作用,從而使耦合鬆散,而且可以獨立地改變它們之間的互動。

這裡寫圖片描述

中介者模式是將多個同事類之間的一對多耦合降低成一對一的星狀耦合。一般情況下一對多的依賴在程式設計中是允許的,沒有必要引用中介這模式。除非在依賴關係過於複雜的情況下,我們才使用中介者降低耦合。

訪問者模式

定義:封裝某些作用於某種資料結構中各元素的操作,它可以在不改變資料結構的前提下定義作用於這些元素的新的操作。

這裡寫圖片描述

    abstract class Element {  
        public abstract void accept(IVisitor visitor);  
        public abstract void doSomething();  
    }  

    interface IVisitor {  
        public void visit(ConcreteElement1 el1);  
        public void visit(ConcreteElement2 el2);  
    }  

    class ConcreteElement1 extends Element {  
        public void doSomething(){  
            System.out.println("這是元素1");  
        }  

        public void accept(IVisitor visitor) {  
            visitor.visit(this);  
        }  
    }  

    class ConcreteElement2 extends Element {  
        public void doSomething(){  
            System.out.println("這是元素2");  
        }  

        public void accept(IVisitor visitor) {  
            visitor.visit(this);  
        }  
    }  
    class Visitor implements IVisitor {  

        public void visit(ConcreteElement1 el1) {  
            el1.doSomething();  
        }  

        public void visit(ConcreteElement2 el2) {  
            el2.doSomething();  
        }  
    }  

    class ObjectStruture {  
        public static List<Element> getList(){  
            List<Element> list = new ArrayList<Element>();  
            Random ran = new Random();  
            for(int i=0; i<10; i++){  
                int a = ran.nextInt(100);  
                if(a>50){  
                    list.add(new ConcreteElement1());  
                }else{  
                    list.add(new ConcreteElement2());  
                }  
            }  
            return list;  
        }  
    }  

    public class Client {  
        public static void main(String[] args){  
            List<Element> list = ObjectStruture.getList();  
            for(Element e: list){  
                e.accept(new Visitor());  
            }  
        }  
    }  

訪問者模式的優點

  • 符合單一職責原則:凡是適用訪問者模式的場景中,元素類中需要封裝在訪問者中的操作必定是與元素類本身關係不大且是易變的操作,符合單一職責原則。
  • 擴充套件性良好:元素類可以通過接受不同的訪問者來實現對不同操作的擴充套件。

引自原文:

但是,訪問者模式並不是那麼完美,它也有著致命的缺陷:增加新的元素類比較困難。通過訪問者模式的程式碼可以看到,在訪問者類中,每一個元素類都有它對應的處理方法,也就是說,每增加一個元素類都需要修改訪問者類(也包括訪問者類的子類或者實現類),修改起來相當麻煩。也就是說,在元素類數目不確定的情況下,應該慎用訪問者模式。所以,訪問者模式比較適用於對已有功能的重構,比如說,一個專案的基本功能已經確定下來,元素類的資料已經基本確定下來不會變了,會變的只是這些元素內的相關操作,這時候,我們可以使用訪問者模式對原有的程式碼進行重構一遍,這樣一來,就可以在不修改各個元素類的情況下,對原有功能進行修改。

最複雜的行為型模式。

責任鏈模式

定義:使多個物件都有機會處理請求,從而避免了請求的傳送者和接收者之間的耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有物件處理它為止。

這裡寫圖片描述

責任鏈模式其實就是一個靈活版的if…else…語句,它就是將這些判定條件的語句放到了各個處理類中。

如果if中的判斷過於負載就可以使用責任鏈。

但是使用責任鏈時一定要注意鏈的順序,以及避免出現死迴圈的情況。

直譯器模式

定義:給定一種語言,定義他的文法的一種表示,並定義一個直譯器,該直譯器使用該表示來解釋語言中句子。

這裡寫圖片描述

基本用不到。