《大話設計模式》——學習筆記之"行爲型模式"(觀察者&模板方法&命令&狀態&職責鏈&解釋器&中介者&訪問者&策略&備忘錄&迭代器)

《大話設計模式》——學習筆記之”行爲型模式”(觀察者&模板方法&命令&狀態&職責鏈&解釋器&中介者&訪問者&策略&備忘錄&迭代器)

觀察者模式

定義: 定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己

<da_014>

Subject類,主題或抽象通知者

abstract class Subject{
    private IList<Observer> observers = new List<Observer>();

    //增加觀察者
    public void Attach(Observer observer){
        observers.Add(observer);
    }

    //移除觀察者
    public void Detach(Observer observer){
        observers.Remove(observer);
    }

    //通知
    public void Notify(){
        foreach(Observer o in observers){
            o.Update();
        }
    }

}

Observer類,抽象觀察者

abstract class Observer{
    public abstract void Update();
}

ConcreteSubject類,具體主題或具體通知者

class ConcreteSubject : Subject{
    private string subjectState;
    //具體被觀察者狀態
    public string SubjectState{
        get {return subjectState;}
        set {subjectState = value;}
    }
}

ConcreteObserver類,具體觀察者

class ConcreteObserver : Observer{
    private string name;
    private string observerState;
    public ConcreteObserver(ConcreteSubject subject, string name){
        this.subject = subject;
        this.name = name;
    }

    public override void Update(){
        observerState = subject.SubjectState;
        Console.WriteLine("觀察者{0}的新狀態是{1}", name, observerState);
    }

    public ConcreteSubject Subject{
        get {return subject;}
        set {subject = value;}
    }

}

客戶端代碼

static void Main(string[] args){
    ConcreteSubject s = new ConcreteSubject();

    s.Attach(new ConcreteObserver(s, "X"));
    s.Attach(new ConcreteObserver(s, "Y"));

    s.SubjectState = "ABC";
    s.Notify();
    Console.Read();
}

優點:

  • 當一個對象的改變需要同時改變其他對象的時候,而且它不知道具體有多少對象有待改變時,就應該考慮使用觀察者模式
  • 觀察者模式所做的工作就是在解除耦合,讓耦合的雙方都依賴於抽象,而不是依賴於具體,從而使得各自的變化都不會影響另一邊的變化
  • 目標和觀察者不是緊密耦合的,它們可以屬於一個系統中的不同抽象層次,目標所知道的僅僅是它有一系列的觀察者,每個觀察者實現Observer的簡單接口,觀察者屬於哪一個具體類,目標是不知道的

模板方式模式

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

<img da_011>

AbstractClass是抽象類,也就是抽象模板,定義並實現了一個模板方法,這個模板方法一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現,頂級邏輯也有可能調用一些具體方法

abstract class AbstractClass{

    //一些抽象行爲,放到子類去實現
    public void PrimitiveOperation1();
    public void PrimitiveOperation2();

    //模板方法,給出了邏輯的骨架,而邏輯的組成是一些相應的抽象操作,它們都推遲到子類實現
    public void TemplateMethod(){
        PrimitiveOperation1();
        PrimitiveOperation2();
        Console.WriteLine("");
    }
}

AbstractClass的實現類

class ConcreteClassA : AbstractClass{
    public override void PrimitiveOperation1(){
        Console.WriteLine("具體類A方法1實現");
    }

    public override PrimitiveOperation2(){
        Console.WriteLine("具體類A方法2實現");
    }
}
...

客戶端調用

static void Main(string[] args){
    AbstractClass c;
    c = new ConcreteClassA();
    c.TemplateMethod();

    Console.Read();
}

優點:

  • 當要完成在某一細節層次一致的一個過程或一系列步驟,但其個別步驟在更詳細的層次上的實現可能不同時,通常考慮用模板方法模式來處理
  • 模板方法模式由一個抽象類組成,這個抽象類定義了需要覆蓋的可能有不同實現的模板方法,每個從這個抽象類派生的具體類將爲此模板實現新方法

命令模式

定義: 將一個請求封裝爲一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤銷的操作

<img da_023>

Command類,用來聲明操作的接口

abstract class Command{
    protected Receiver receiver;

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

    abstract public void Execute();
}

ConcreteCommand類,將一個接收者對象綁定於一個動作,調用接收者相應的操作,以實現Execute

class ConcreteCommand : Command{
    public ConcreteCommand(Receiver receiver) : base(receiver){

    }

    public override void Execute(){
        receiver.Action();
    }
}

Invoker類,要求該命令執行這個請求

class Invoker{
    private Command command;

    public void SetCommand(Command command){
        this.command = command;
    }

    public void ExecuteCommand(){
        command.Execute();
    }
}

Receiver類,知道如何實施與執行一個與請求相關的操作,任何類都可能作爲一個接收者

class Receiver{
    public void Action(){
        Console.WriteLine("執行請求!");
    }
}

客戶端代碼,創建一個具體命令對象並設定它的接收者

static void Main(string[] args){
    Receiver r = new Receiver();
    Command c = new ConcreteCommand(r);
    Invoker i = new Invoker();
    i.SetCommand(c);
    i.ExecuteCommand();

    Console.Read();
}

優點:

  • 較容易地設計一個命令隊列
  • 在需要的情況下,可以較容易地將命令記入日誌
  • 允許接收請求的一方決定是否要否決請求
  • 可以容易地實現對請求的撤銷和重做
  • 由於加進新的具體命令類不影響其他的類,因此增加新的具體命令類很容易
  • 命令模式把請求一個操作的對象與知道怎麼執行一個操作的對象分割開

狀態模式

定義:狀態模式(State),當一個對象的內在狀態改變時允許改變其行爲,這個對象看起來像是改變了其類

<img da_016>

State類,抽象狀態類,定義一個接口以封裝與Context的一個特定狀態相關的行爲

abstract class State{
    public abstract void Handle(Context context);
}

ConcreteState類,具體狀態,每一個子類實現一個與Context的一個狀態相關的行爲

class ConcreteStateA : State{
    public override void Handle(Context context){
        //設置ConcreteStateA的下一狀態是ConcreteStateB
        context.State = new ConcreteStateB();
    }
}

class ConcreteStateB : State{
    public override void Handle(Context context){
        //設置ConcreteStateB的下一狀態是ConcreteStateA
        context.State = new ConcreteStateA();
    }
}

Context類,維護一個ConcreteState子類的實例,這個實例定義當前的狀態

class Context{
    private State state;
    //定義Context的初始狀態
    public Context(State state){
        this.state = state;
    }

    //可讀寫的狀態屬性,用於讀取當前狀態和設置新狀態
    public State state{
        get(return state;)
        set{
            state = value;
            Console.WriteLine("當前狀態:" + state.GetType().Name);
        }
    }

    public void Request(){
        //對請求做處理,並設置下一狀態
        state.Handle(this);
    }
}

客戶端代碼

static void Main(string[] args){
    Context c = new Context(new ConcreteStateA());

    //不斷的請求,同時改變狀態
    c.Request();
    c.Request();
    c.Request();

    Console.Read();
}

好處:

  • 狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的情況,把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把複雜的判斷邏輯簡化
  • 將特定的狀態相關的行爲都放入一個對象中,由於所有與狀態相關的代碼都存在於某個ConcreteState中,所以通過定義新的子類可以很容易地增加新的狀態和轉換
  • 可以消除龐大的條件分支語句,通過把各種狀態轉移邏輯分佈到State的子類之間,來減少相互間的依賴
  • 當一個對象的行爲取決於它的狀態,並且它必須在運行時刻根據狀態改變它的行爲時,就可以考慮使用狀態模式

職責鏈模式

定義: 使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係,將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止

<da_024>

Handler類,定義一個處理請示的接口

abstract class Handler{
    protected Handler successor;

    public void SetSuccessor(Handler successor){ //設置繼任者
        this.successor = successor;
    }

    public abstract void HandleRequest(int request); //處理請求的抽象方法
}

ConcreteHandler類,具體處理者類,處理它所負責的請求,可訪問它的後繼者,如果可處理該請求就處理,否則就將該請求轉發給它的後繼者

ConcreteHandler1,請請求數在0到10之間則有權處理,否則轉到下一位

class ConcreteHandler1 : Handler{
    public override void HandleRequest(int request){
        //處理此請求
        if(request >= 0 && request < 10){
            Console.WriteLine("{0} 處理請求 {1}", this.GetType().Name, request);
        } else if(successor != null){
            //轉移到下一位
            successor.HandleRequest(request);
        }
    }
}

ConcreteHandler2,當請求數在10到20之間則有權處理,否則轉到下一位

class ConcreteHandler1 : Handler{
    public override void HandleRequest(int request){
        //處理此請求
        if(request >= 10 && request < 20){
            Console.WriteLine("{0} 處理請求 {1}", this.GetType().Name, request);
        } else if(successor != null){
            //轉移到下一位
            successor.HandleRequest(request);
        }
    }
}

客戶端代碼

static void Main(string[] args){
    Handler h1 = new ConcreteHandler1();
    Handler h2 = new ConcreteHandler2();
    h1.SetSuccessor(h2);

    int[] requests = {2, 5, 14};

    foreach(int request in requests){
        h1.HandleRequest(request);
    }

    Console.Read();
}

優點:

  • 當客戶提交一個請求時,請求是沿鏈傳遞直至有一個ConcreteHandler對象負責處理它
  • 鏈中的對象自己並不知道鏈的結構,結果是職責鏈可簡化對象的相互連接
  • 可以動態地增加或修改處理一個請求的結構,增強了給對象指派職責的靈活性
  • 使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係,將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止
  • 有多個對象可以處理一個請求,哪個對象處理該請求事先並不知道,要在運行時刻自動確定,讓請求發送者與具體處理者分離,讓客戶在不明確指定接收者的情況下,提交一個請求,然後由所有能處理這請求的對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止

解釋器模式

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

AbstractExpression(抽象表達式),聲明一個抽象的解釋操作,這個接口爲抽象語法樹中所有的節點所共享

abstract class AbstractExpression{
    public abstract void Interpret(Context context);
}

TerminalExpression(終結符表達式),實現與文法中的終結符相關聯的解釋操作,實現抽象表達式中所要求的接口,主要是一個interpret()方法,文法中每一個終結符都有一個具體終結表達式與之相對應

class TerminalExpression : AbstractExpression{
    public override void Interpret(Context context){
        Console.WriteLine("終端解釋器");
    }
}

NonterminalExpression(非終結符表達式),爲文法中的非終結符實現解釋操作,對文法中每一條規則R1,、R2…Rn都需要一個具體的非終結符表達式類,通過實現抽象表達式的interpret()方法實現解釋操作,解釋操作以遞歸方式調用上面所提到的代表R1、R2…Rn中各個符合的實例變量

class NonterminalExpression : AbstractExpression{
    public override void Interpret(Context context){
        Console.WriteLine("非終端解釋器");
    }
}

Context,包含解釋器之外的一些全局信息

class Context{
    private string input;
    private string Input{
        get {return input;}
        set {input = value;};
    }

    private string output;
    private string Output{
        get {return output;}
        set {output = value;};
    }
}

客戶端代碼,構建表示該文法定義的語言中一個特定的句子的抽象語法樹,調用解釋操作

static void Main(string[] args){
    Context context = new Context();
    IList<AbstractExpression> list = new List<AbstractExpression>();
    list.Add(new TerminalExpression());
    list.Add(new NonterminalExpression());
    list.Add(new TerminalExpression());
    list.Add(new TerminalExpression());

    foreach (AbstractExpression exp in list){
        exp.Interpret(context);
    }

    Console.Read();
}

優點:

  • 當有一個語言需要解釋執行,並且可將語言中的句子表示爲一個抽象語法樹時,可使用解釋器模式
  • 可以很容易地改變和擴展文法,因爲該模式使用類來表示文法規則,可使用繼承來改變或擴展該文法,也比較容易實現文法,因爲定義抽象語法樹中各個節點的類的實現大體類似,這些類都易於直接編寫
  • 如果一種特定類型的問題發生的頻率足夠高,那麼就可以考慮將該問題的各個實例表述爲一個簡單語言的句子,也就是說,通過構建一個解釋器,該解釋器解釋這些句子來解決該問題(如正則表達式)

缺點:

  • 解釋器模式爲文法中的每一條規則至少定義了一個類,因此包含許多規則的文法可能難以管理和維護,建議當文法非常複雜時,使用其他的技術如語法分析程序或編譯器生成器來處理

中介者模式

定義: 用一箇中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互

<da_025>

Mediator類,抽象中介者類

abstract class Mediator{
    public abstract void Send(string message, Colleague colleague); // 定義一個抽象的發送消息方法,得到同事對象和發送消息
}

Colleague類,抽象同事類

abstract class Colleague{
    protected Mediator mediator;

    public Colleague(Mediator mediator){
        this.mediator = mediator;// 構造方法,得到中介者對象
    }
}

ConcreteMediator類,具體中介者類

class ConcreteMediator : Mediator{
    private ConcreteColleague1 colleague1;
    private ConcreteColleague1 colleague1;

    public ConcreteColleague1 Colleague1{
        set {colleague1 = value;}
    }

    public ConcreteColleague2 Colleague2{
        set {colleague2 = value;}
    }

    public override void Send(string message, Colleague colleague){
        if(colleague == colleague1){
            colleague2.Notify(message);
        } else {
            colleague1.Notify(message);
        }
    }
}

具體的同事對象

class ConcreteColleague1 : Colleague{
    public ConcreteColleague1(Mediator mediator) : base(mediator){

    }

    public void Send(string message){
        // 發送消息時通常是中介者發送出去的
        mediator.Send(message, this);
    }

    public void Notify(string message){
        Console.WriteLine("同事1得到消息:" + message);
    }
}

class ConcreteColleague2 : Colleague{
    public ConcreteColleague2(Mediator mediator) : base(mediator){

    }

    public void Send(string message){
        // 發送消息時通常是中介者發送出去的
        mediator.Send(message, this);
    }

    public void Notify(string message){
        Console.WriteLine("同事2得到消息:" + message);
    }
}

客戶端調用:

static void Main(string[] args){
    ConcreteMediator m = new ConcreteMediator();

    //讓兩個具體同事類認識中介者對象
    ConcreteColleague1 c1 = new ConcreteColleague1(m);
    ConcreteColleague2 c2 = new ConcreteColleague2(m);

    //讓中介者認識各個具體同事類對象
    m.Colleague1 = c1;
    m.Colleague2 = c2;

    c1.Send("吃過飯了嗎?");
    c2.Send("沒有呢");

    Console.Read();
}

優點:

  • Mediator的出現減少了各個Colleague的耦合,使得可以獨立地改變和複用各個Colleague類和Mediator
  • 由於把對象如何協作進行了抽象,將中介作爲一個獨立的概念並將其封裝在一個對象中,這樣關注的對象就從對象各自本身的行爲轉移到它們之間的交互上來
  • 中介者模式一般應用於一組對象以定義良好但是複雜的方式進行通信的場合,以及想定製一個分佈在多個類中的行爲,而又不想生成太多的子類的場合
  • 用一箇中介對象來封裝一系列的對象交互,中介者使各對象不需要顯示地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互
  • 對象間有許多連接,使得一個對象不大可能在沒有其他對象的支持下工作,這對於應對變化是不利的
  • 將集體行爲封裝一個單獨的中介者對象來避免整個問題,中介者負責控制和協調一組對象間的交互,中介者充當一箇中介以使組中的對象不再相互顯示引用,這些對象僅知道中介者,從而減少了相互連接的數目

缺點:

  • 由於ConcreteMediator控制了集中化,於是就把交互複雜性變爲了中介者的複雜性,這就使得中介者會變得比任何一個ConcreteColleague都複雜(當系統出現了”多對多”交互複雜的對象羣時,不要急於使用中介者模式,而要先反思系統在設計上是否合理)

訪問者模式

定義: 表示一個作用於某對象結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作

這裏寫圖片描述

Visitor類,爲該對象結構中ConcreteElement的每一個類聲明一個Visit操作

abstract class Visitor{
    public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);
    public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}

ConcreteVisitor1和ConcreteVisitor2,類,具體訪問者,實現每個由Visitor聲明的操作,每個操作實現算法的一部分,而該算法片斷乃是對應於結構中對象的類

class ConcreteVisitor1 : Visitor{
    public override void VisitConcreteElementA(ConcreteElementA concreteElementA){
        Console.WriteLine("{0}被{1}訪問", concreteElementA.GetType().Name, this.GetType().Name);
    }

    public override void VisitConcreteElementB(ConcreteElementB concreteElementB){
        Console.WriteLine("{0}被{1}訪問", concreteElementB.GetType().Name, this.GetType().Name);
    }
}

class ConcreteVisitor1 : Visitor{
    ...
}

Element類,定義一個Accept操作,它以一個訪問者爲參數

abstract class Element{
    public abstract void Accept(Visitor visitor);
}

ConcreteElementA和ConcreteElementB類,具體元素,實現Accept操作

class ConcreteElementA : Element{
    public override void Accept(Visitor visitor){
        //充分利用雙分派技術,實現處理與數據結構的分離
        visitor.VisitConcreteElementA(this);
    }

    public void OperationA(){

    }
}

class ConcreteElementB : Element{
    public override void Accept(Visitor visitor){
        //充分利用雙分派技術,實現處理與數據結構的分離
        visitor.VisitConcreteElementB(this);
    }

    public void OperationB(){

    }
}

ObjectStructure類,能枚舉它的元素,可以提供一個高層的接口以允許訪問者訪問它的元素

class ObjectStructure{
    private IList<Element> elements = new List<Element>();

    public void Attach(Element element){
        elements.Add(element);
    }

    public void Detach(Element element){
        elements.Remove(element);
    }

    public void Accept(Visitor visitor){
        foreach (Element e in elements){
            e.Accept(visitor);
        }
    }
}

客戶端代碼

static void Main(string[] args){
    ObjectStructure o = new ObjectStructure();
    o.Attach(new ConcreteElementA());
    o.Attach(new ConcreteElementB());

    ConcreteVisitor1 v1 = new ConcreteVisitor1();
    ConcreteVisitor2 v2 = new ConcreteVisitor2();

    o.Accept(v1);
    o.Accept(v2);

    Console.Read();
}

優點:

  • 訪問者模式適用於數據結構相對穩定的系統
  • 把數據結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化
  • 訪問者模式的目的是要把處理從數據結構分離出來,如果系統有比較穩定的數據結構,又有易於變化的算法的話,使用訪問者模式就比較合適,因爲訪問者模式使得算法操作的增加變得容易
  • 訪問者模式的優點就是增加新的操作很容易,因爲增加新的操作就意味着增加一個新的訪問者,訪問者模式將有關的行爲集中到一個訪問者對象中
  • 訪問者增加具體的Element是困難的,但增加依賴於複雜對象結構的構件的操作就變得很容易,僅需增加一個新的訪問者即可在一個對象結構上定義一個新的操作

缺點:

  • 使增加新的數據結構變得困難了(大多數情況下並不需要訪問者模式,因爲很難找到數據結構不變化的情況)

策略模式

定義:定義了算法家族,分別封裝起來,讓它們之間可以相互替換,此模式讓算法的變化不會影響到使用算法的客戶

<img da_003>

Strategy類,定義了所有支持的算法的公共接口

//抽象算法類
abstract class Strategy{
    //算法方法
    public abstract void AlgorithmInterface();
}

ConcreteStrategy類,封裝了具體的算法或行爲,繼承於Strategy

//具體算法A
class ConcreteStrategyA : Strategy{
    //算法A實現方法
    public override void AlgorithmInterface(){
        Console.WriteLine("算法A實現");
    }
}

//算法B
...

Context,用一個ConcreteStrategy來配置,維護一個對Strategy對象的引用

//上下文
class Context{
    Strategy strategy;
    //初始化時,傳入具體的策略對象
    public Context(Strategy strategy){
        this.strategy = strategy;
    }

    //上下文接口
    //根據具體的策略對象,調用其算法的方法
    public void ContextInterface(){
        strategy.AlgorithmInterface();
    }
}

客戶端代碼

static void Main(string[] args){
    Context context;
    context = new Context(new ConcreteStrategyA());
    context.ContextInterface();

    context;
    context = new Context(new ConcreteStrategyB());
    context.ContextInterface();
    ...
}

優點:

  • 策略模式是一種定義一系列算法的方法,從概念上來看,所有這些算法完成的都是相同的工作,只是實現不同,它可以以相同的方式調用所有的算法,減少了各個算法類與使用算法類之間的耦合
  • 策略模式的Strategy類層次爲Context定義了一系列的可供重用的算法或行爲,繼承有助於析取出這些算法中的公共功能
  • 策略模式的優點是簡化了單元測試,因爲每個算法都有自己的類,可以通過自己的接口單獨測試
  • 繼承提供了一種支持多種算法或行爲的方法,我們可以生成一個類A的子類B、C、D,從而給它以不同的行爲,但這樣會將行爲硬行編制到父類A當中,而將算法的實現與類A的實現混合起來,從而使得類A難以理解、難以維護和難以擴展,而且還不能動態地改變算法
  • 將算法封裝在獨立的策略Strategy類中使得你可以獨立於其類A改變它,使它易於切換、易於理解、易於擴展
  • 當不同的行爲堆砌在一個類中時,就很難避免使用條件語句來選擇合適的行爲,將這些行爲封裝在一個個獨立的Strategy類中,可以在使用這些行爲的類中消除條件語句
  • 策略模式是用來封裝算法的,但在實踐中,我們發現可以用它來封裝幾乎任何類型的規則,只要在分析過程中聽到需要在不同時間應用不同的業務規則,就可以考慮使用策略模式來處理這種變化的可能性
  • 定義一系列的算法,把它們一個個封裝起來,並且使它們可相互替換,本模式使得算法可獨立於使用它的客戶而變化

備忘錄模式

定義:備忘錄(Memento):在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣以後就可將對象恢復到原先保存的狀態

<img da_018>

發起人(Originator)類

class Originator{
    private string state;
    public string State{
        //需要保存的屬性,可能有多個
        get{ return state; }
        set{ state = value; }
    }

    //創建備忘錄,將當前需要保存的信息導入並實例化出一個Memento對象
    public Memento CreateMemento(){
        return (new Memento(state));
    }

    //恢復備忘錄,將Memento導入並將相關數據恢復
    public void SetMemento(Memento memento){
        state = memento.State;
    }

    public void Show(){
        Console.WriteLine("State = " + state);
    }
}

備忘錄(Memento)類

class Memento{
    private string state;

    //構造方法,將相關數據導入
    public Memento(string state){
        this.state = state;
    }

    //需要保存的數據屬性,可以是多個
    public string State{
        get { return state; }
    }
}

管理者(Caretaker)類

class Caretaker{
    private Memento memento;

    public Memento Memento{
        get { return memento; }
        set { memento = value; }
    }
}

客戶端程序

static void Main(string[] args){
    //Originator初始狀態,狀態屬性爲"On"
    Originator o = new Originator();
    o.State = "On";
    o.Show();

    //保存狀態,隱藏了Originator的實現細節
    Caretaker c = new Caretaker();
    c.Memento = o.CreateMemento();

    o.State = "Off";
    o.Show();

    //恢復原初始狀態
    o.SetMemento(c.Memento);
    o.Show();

    Console.Read();
}

優點:

  • Memento模式適用於功能比較複雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是衆多屬性中的一小部分時,Originator可以根據保存的Memento信息還原到前一狀態
  • 使用備忘錄可以把複雜的對象內部信息對其他的對象屏蔽起來
  • 在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣以後就可將該對象恢復到原先保存的狀態
  • 可以避免暴露一些只應由對象A管理卻又必須存儲在對象A之外的信息,備忘錄模式把可能很複雜的對象A的內部信息對其他對象屏蔽起來,從而保持了封裝邊界

迭代器模式

定義: 提供一種方法順序訪問一個聚合對象中各個元素,而又不暴露該對象的內部表示

<img da_020>

迭代接口

public interface IEnumerator{
    object Current{
        get;
    }
    bool MoveNext();
    void Reset(); //恢復初始化指向的位置,該位置位於集合中第一個元素之前
}

IEnumerable公開枚舉數,該枚舉數支持在非泛型集合上進行簡單迭代

public interface IEnumerable{
    IEnumerator GetEnumerator(); //返回一個循環訪問集合的枚舉數
}

客戶端代碼

static void Main(string[] args){
    IList<string> a = new List<string>();
    a.Add("..");
    ...

    foreach (string item in a){
        Console.WriteLine("{0} ...", item);
    }
    //foreach in中做的操作如下:
    // IEnumerator<string> e = a.GetEnumerator();
    // while(e.MoveNext()){
    //    Console.WriteLine(...);    
    // }
    Console.Read();
}

優點:

  • 爲遍歷不同的聚集結構提供如開始、下一個、是否結束、當前哪一項等統一的接口
  • 迭代器模式分離了集合對象的遍歷行爲,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據
  • 需要訪問一個聚集對象,而且不管這些對象是什麼都需要遍歷的時候,就應該考慮用迭代器模式
  • 當需要對聚集有多種方式遍歷時(從前往後/從後往前),可以考慮用迭代器模式
發佈了84 篇原創文章 · 獲贊 135 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章