把委托說透(4):委托與設計模式

作者: 麒麟.NET  來源: 博客園  發布時間: 2009-09-08 09:50  閱讀: 4163 次  推薦: 0   原文鏈接   [收藏]  
摘要:本文重點討論委托與設計模式的關系,包括觀察者模式和模板方法模式。您是否覺得委托與其他方法也有關系呢?不妨在回復中進行討論。

委托與很多設計模式都有著千絲萬縷的聯系,在前面的隨筆中已經介紹了委托與策略模式的聯系,本節主要來討論委托與其他兩個模式:觀察者模式和模板方法模式。

委托與觀察者模式

在.NET中,很多設計模式得到了廣泛應用,如foreach關鍵字實現了迭代器模式。同樣的,.NET中也內置了觀察者模式的實現方式,這種方式就是委托。

觀察者模式的一般實現

網上可以找到很多資料介紹觀察者模式的實現,我這里介紹一種簡單的退化后的觀察者模式,即Subject類為具體類,在其之上不再進行抽象。

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

    private string state;
    public string State
    {
        set
        {
            state = value;
            NotifyObservers();
        }
        get { return state; }
    }

    public void RegisterObserver(Observer ob)
    {
        observers.Add(ob);
    }

    public void RemoveObserver(Observer ob)
    {
        observers.Remove(ob);
    }

    public void NotifyObservers()
    {
        foreach (Observer ob in observers)
            ob.Update(this);
    }
}

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

public class ConsoleObserver : Observer
{
    public ConsoleObserver(Subject subject)
    {
        subject.RegisterObserver(this);
    }

    public override void Update(Subject subject)
    {
        Console.WriteLine("Subject has changed its state : " + subject.State);
    }
}

 

調用的方法很簡單:

Subject subject = new Subject();
Observer observer = new ConsoleObserver(subject);
subject.State = "Kirin Yao";

Subject類維護一個列表,負責觀察者的注冊和移除。當其狀態發生改變時,就調用NotifyObservers方法通知各個觀察者。

觀察者模式的委托實現

在.NET中,使用委托可以更簡單更優雅地實現觀察者模式。在上一篇隨筆中,最后的示例其實就是一個觀察者模式。MainForm為Subject,SubForm為Observer。當MainForm的狀態發生改變時(即點擊“傳值”按鈕時),SubForm作為觀察者響應來自MainForm的變化。

與上例對應的,用委托實現的觀察者模式的代碼大致如下:

namespace DelegateSample
{
    class UpdateEventArgs : EventArgs { }

    class Subject
    {
        private string state;

        public string State 
        {
            get { return state; }
            set 
            {
                state = value;
                OnUpdate(new UpdateEventArgs());
            }
        }

        public event EventHandler<UpdateEventArgs> Update;

        public void ChangeState(string state)
        {
            this.State = state;
            OnUpdate(new UpdateEventArgs());
        }

        private void OnUpdate(UpdateEventArgs e)
        {
            EventHandler<UpdateEventArgs> handler = Update;
            if (handler != null)
                Update(this, e);
        }
    }

    abstract class Observer
    {
        public Subject Subject { get; set; }

        public Observer(Subject subject)
        {
            this.Subject = subject;
            this.Subject.Update += new EventHandler<UpdateEventArgs>(Subject_Update);
        }

        protected abstract void Subject_Update(object sender, UpdateEventArgs e);
    }

    class ConsoleObserver : Observer
    {
        public ConsoleObserver(Subject subject) : base(subject) { }

        protected override void Subject_Update(object sender, UpdateEventArgs e)
        {
            Subject subject = sender as Subject;
            if (subject != null)
                Console.WriteLine("Subject has changed its state : " + subject.State);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Subject subject = new Subject();
            Observer ob = new ConsoleObserver(subject);
            subject.State = "Kirin Yao";
            Console.ReadLine();
        }
    }
}

 

相比傳統的觀察者模式的實現方式(在Subject中維護一個Observer列表),使用委托避免了Subject與Observer之間的雙向引用,Subject作為主題類,對觀察者毫無所知,降低了耦合性,語法上也更加優雅。

委托與模板方法模式

模板方法模式封裝了一段通用的邏輯,將邏輯中的特定部分交給子類實現。

public abstract class AbstractClass
{
    public void Arithmetic()
    {
        SubArithmeticA();
        SubArithmeticB();
        SubArithmeticC();
    }

    protected abstract void SubArithmeticA();
    protected abstract void SubArithmeticB();
    protected abstract void SubArithmeticC();
}

public class ConcreteClass : AbstractClass
{
    protected override void SubArithmeticA()
    {
        //...
    }

    protected override void SubArithmeticB()
    {
        //...
    }

    protected override void SubArithmeticC()
    {
        //...
    }
}

然而這種繼承方式的模板方法耦合度較高,特別是如果邏輯與其外部實現沒有必然的從屬關系的時候,用傳統的模板方法就顯得不那么合適了。

在某種程度上,委托可以看做是一個輕量級的模板方法實現方式,它將邏輯中的特定部分轉交給注冊到委托的方法來實現。從而替代了繼承方式的模板方法模式中,在子類中實現特定邏輯的方式。

public delegate void SubArithmetic();

public class ConcreteClass
{
    public void Arithmetic()
    {
        if (SubArithmetic != null)
            SubArithmetic();
    }

    public SubArithmetic SubArithmetic { get; set; }
}

 

而SubArithmetic的實現交給外部:

ConcreteClass concrete = new ConcreteClass();
concrete.SubArithmetic = Program.SomeMethod;
concrete.Arithmetic();

咋一看在客戶端中編寫委托的方法似乎還略顯麻煩,但值得注意的是,匿名方法和Lambda表達式為我們提供了更加簡便的委托語法。在函數式編程日益盛行的今天,我們應該為.NET提供的這種語言特性而感到慶幸。

0
0
 
標簽:delegate CLR
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()