最近,Microsoft越来越强调设计模式。如果你不熟悉设计模式,那么你会被这些新的术语和从来没有看见到的UML图所淹没。这次对设计模式的强调,相对于词汇的变化来讲,在方法论上并没有太多的变换,因为Microsoft® .NET Framework base class library (BCL)已经在设计模式上已经有了很广泛的应用。您其实已经接触到了这些模式,只是你没有意识到而已。在这篇文章里,我将会阐述一下几种基本模式的大概情况以及在BCLframework中其他方面是如何使用到他们的。看了这些后,你会发现Framework为什么会这么设计的动机,并且能对设计模式的抽象概念有一个直观的了解。

这里我提及到的模式大部分都是来源于由Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides撰写的《设计模式》这本书。他们就是四人帮。其实,四人帮并没有发明这些模式,但是他们把自软件开发以来别人已经做出来的好的设计加以文档化和正式化,从而形成设计模式。

如果你已经很熟悉设计模式,那么你在读这篇文章时会轻松自如,因为这些章节都是独立的,彼此之间没有什么太多的联系。有关于ASPNET 章节要求你要对请求管道熟悉,在那些章节里,我们会对请求管道有些大概的了解。

.NET Framework里,有些模式实在是太普遍了,它们常常会内置在程序语言里,而不仅仅在类库中体现。我将要讨论的前两个模式----Observer(观察者)Iterator(迭代器)模式,都已经有C#VBNET的语言特性所支持。就像你将要看到的一样,他们是很多常规的编程工作主要的部分。

Observer :观察者,需要目标对象在发现变化时能获得通知并调用本身某个更新的方法。

Subejct : 目标,即当本身发现变化时能通知每一个观察者。

    好的 OO 设计不但强调封装而且还强调松耦合,换句话说,类要尽可能的封装自己内部的私有细节并且应该将类与类之间的强依赖减小到最少。在大多数应用里,类并不是孤立的,它们之间往往会相互交互和影响。这里有一个很普遍的类与类交互场景:当一个对象( subject )发生改变时,另外一个对象( Observer )要求能收到这个 (subject 改变的 ) 通知。例如:几个窗体控件需要在一个按钮点击后能够改变它们的呈现。一个简单的解决方法就是在 Subject 对象状态改变时直接去调用 Observer 的某一个特定的方法。这种方法将会引入一大把问题:

Subject 需要知道将要调用 Observer 哪一个方法,这种情况将会导致 Subject 与某个特定的 Observer 紧耦合。此外,如果你需要添加另外几个 Observer ,你不得不在 Subject 里添加调用每一个 Observer 方法的代码。如果 Observer 的数量是动态变化的,那么这将更加复杂,你将倒在这种无法维护的混乱之中。

       一个有效的解决方法是使用观察者模式。使用这种方法,你能够将 Subject 与它的那些 Observer 解耦以便能在设计时和运行时轻松的添加和删除任意数量的 Observer Subject 维护着一个 Observer 的列表,每当 Subject 的状态有所改变时,它能够依次通知列表中所有的 Observer 。请看如下的示例代码:

public abstract class CanonicalSubjectBase

{

private ArrayList _observers = new ArrayList();

public void Add(ICanonicalObserver o)

    {

        _observers.Add(o);

}

public void Remove(ICanonicalObserver o)

    {

        _observers.Remove(o);

    }

public void Notify()

    {

        foreach(ICanonicalObserver o in _observers)

        {

            o.Notify();

        }

    }

}

public interface ICanonicalObserver

{

    void Notify();

}

    所有的扮演 Observer 角色的类都实现了 ICanonicalObserver 接口,所有的 Subject 都必须继承自 CanonicalSubjectBase ,如果有一个新的 Observer 想监测 Object ,那么只需要添加此 Observer 的方法而不需要更改 Subject 中的任何一行代码! 而且你会发现 Object 再也不用直接依赖于那些 Observer (因为开始的那个方式是 Object 必须调用每个 Observer 的某个方法,译者注)了,而是仅仅依赖于 ICanonicalObserver 接口。

        尽管四人帮的观察者模式能够解决一些问题,但是这个方式还是有些缺陷,因为 Subejct 必须继承自 CanonicalSubjectBase ,所有的 Observer 必须实现 ICanonicalObserver 接口。(也就是说从一种意义上的紧耦合转移成了另一种意义上的耦合,译者注) , 让我们回头看看那个窗体按钮控件的例子吧,解决的方案就呈现在我们眼前: NET Framework 使用委托和事件来解决这个问题!如果你曾经在 ASP.NET WinForm 中写过程序,那么你可能已经使用过委托和事件,事件就是 Subejct ,而委托就是 Observer ,让我们来看看利用事件来实现的观察者模式的例子:

public delegate void Event1Hander();

public delegate void Event2Handler(int a);

public class Subject

{

public Subject(){}

public Event1Hander Event1;

 public Event2Handler Event2;

public void RaiseEvent1()

 {

     Event1Handler ev = Event1;

     if (ev != null) ev();

   }

public void RaiseEvent2()

 {

     Event2Handler ev = Event2;

     if (ev != null) ev(6);

 }

}

public class Observer1

{  public Observer1(Subject s)

    {

        s.Event1 += new Event1Hander(HandleEvent1);

        s.Event2 += new Event2Handler(HandleEvent2);

}

public void HandleEvent1()

    {

      Console.WriteLine("Observer 1 - Event 1");

}

public void HandleEvent2(int a)

    {

        Console.WriteLine("Observer 1 - Event 2");

    }

}

     窗体按钮控件暴露了一个在按钮点击时能够通知 Observer 的点击事件,任何一个需要响应该事件的 Observer 仅仅只需要向这个事件注册一个委托( new Event1Hander method )便是一个委托,注册一个委托就是 += Event1 事件,译者注)。窗体按钮控件并不依赖于任何一个潜在的 Observer ,每一个 Observer 仅仅只需要知道这个事件的委托签名格式就 OK 了(在这个实例里委托就是 EventHandler ),因为 EventHandler 是一个委托类型而不是一个接口,所以每个 Observer 不需要去实现一个格外的接口,如果一个 Observer 已经有了一个符合委托签名格式的方法,那么它仅仅只需要把这个方法注册到 Subject 的事件中去。通过使用委托和事件,观察者模式能将 Subject Observer 解耦(也就是 Subject 不需要显式的去调用 Observer 的某一个方法)!

posted on 2006-04-13 16:36  拉登·闸  阅读(285)  评论(0编辑  收藏  举报