现在的位置: 首页 > 综合 > 正文

初读Observer模式

2012年12月03日 ⁄ 综合 ⁄ 共 5081字 ⁄ 字号 评论关闭
 

初读Observer模式

动机(Motivation)

在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”--一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象(都将得到通知。如果这样的依赖关系过于紧密,将合软件不能很好地抵御变化。

细节依赖抽象,不稳定的去依赖稳定的,软件就会变得松耦合。

使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。

意图(Intent)

定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

 

public class ATM

{

    BankAccount bakAccount;

   

    void process(int data);

    {

       bakAccount.Withdraw(data);

    }

}

 

public class BankAccount

{

    Emailer emailer; //强依赖关系

    Mobile mobile;    //强依赖关系

 

    public void Withdraw(int data)

    {

       //...

      

       emailer.SendEmail(userEmail);

       mobile.SendNotification(phoneNumber);

    }

}

 

public class Emailer

{

    public void SendEmail(string toAddress)

    {

       //...

    }

}

 

public class Mobile

{

    public void SendNotification(string phoneNumber)

    {

       //...

    }

}

 

Observer模式的几个要点

l      使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。(这里的改变,是指扩展)

l      目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。观察者自己决定是否需要订阅通知,目标对象对此一无所知。

l      在C#的event中,委托充当了抽象的Observer接口,而提供事件的对象充当了目标对象。委托是比抽象Observer接口更为松耦合的设计。

 

public abstract class Subject

{

    ArrayList<IAccountObserver> observerList = new ArrayList<IAccountObserver>();

 

    protected virtual void Notify(UserAccountArgs args) <-参数

    {

       [提]/*

       UserAccountArgs args = new UserAccountArgs();

       //...

       */

       foreach(IAccountObserver observer in observerList)

       {

           observer.Update(args);

       }

    }

   

    public void AddObserver(IAccountObserver observer)

    {

       observerList.Add(observer);

    }

    public void RemoveObserver(IAccountObserver observer)

    {

       observerList.Remove(observer);

    }

}

 

[改]public class BankAccount : Subject

{

    public void Withdraw(int data)

    {

       //...

       UserAccountArgs args = new UserAccountArgs();

      

       //... 设置属性

       Notify();

    }

}

 

class App

{

    public static void Main()

    {

       Subject subject = new Subject();

      

       IObserver observer = new Emailer();

      

       subject.Add(observer);

      

       //...

      

       bankAccount.Withdraw(234);

    }

}

 

public interface IAccountObserver

{

    void Update(UserAccountArgs args);

}

 

public class Emailer : IAccountObserver

{

    public void Update(UserAccountArgs args)

    {

       //...

       string toAddress = args.ToAddress;

    }

}

 

public class Mobile : IAccountObserver

{

    public void Update(UserAccountArgs args)

    {

       //...

       string mobileNumber = args.MobileNumber;

    }

}

 

public class BankAccount :Subject

{

    //IAccountObserver emailer; //弱依赖关系(依赖的是一个接口,面向接口编程是因为接口稳定嘛)

   

    ArrayList<IAccountObserver> observerList = new ArrayList<IAccountObserver>();

   

    public void Withdraw(int data)

    {

       //...

      

       /*[提]UserAccountArgs args = new UserAccountArgs(); */

       //...

      

       //emailer.Update(userEmail);

      

       [提]/*

       foreach(IAccountObserver observer in observerList)

       {

           observer.Update(args);

       }

       */

    }

   

    [提]/*

    public void Notify(UserAccountArgs args) <-参数

    {

       [提]/*

       UserAccountArgs args = new UserAccountArgs();

       //...

       */

       foreach(IAccountObserver observer in observerList)

       {

           observer.Update(args);

       }

    }

   

    public void AddObserver(IAccountObserver observer)

    {

       observerList.Add(observer);

    }

    public void RemoveObserver(IAccountObserver observer)

    {

       observerList.Remove(observer);

    }

    */

}

 

难点1:Update中参数的抽取,这里在接口中定义UserAccountArgs

难点2:对于BankAccount类中多个IAccountObserver对象的处理,因为有两个,一个emailer,一个mobile,所以很容易想到用集合的方式来处理

难点3:要让BankAccount依赖稳定的,那么还要抽提出foreach(IAccountObserver observer in observerList)这一部分

 

 

public delegate void AccountChangeEventHandler( //-->接口 表达一个约定,在强类型语言下要保证语法安全

    object sender,

    AccountChangeEventArgs args);   //委托最后会被转化成一个类,其本身就是一个类,内部可以理解为一个链表

                                //一个Add,Remove方法,相当于前面的Subject中的Arraylist<>和Add,Remove

                                //interface的约定比delegate更严格

public class BankAccount : Subject

{

    public event AccountChangeEventHandler AccountChange;

 

 

    public void Withdraw(int data)

    {

       //...

   

       UserAccountArgs args = new UserAccountArgs();

       //..

      

       OnAccountChange(args);

    }

   

    protected virtual OnAccountChange(AccountChangeEventArgs args) //相当于之前NOtify方法

    {

       if(AccountChange != null)   //这里需要一个小小的CHECK,担心事件为空,之前OO模型不

                                //需要Check,是因为它Subject一上去就给New ArrayList了

       {

           AccountChange(args); //在一个委托类型的字段上去调用一个方法的时候,它会按照多波

                                //委托的方式一直调用下去,把委托链上的所有委托都调用一遍

                                //其实就是一个遍历,跟前OO的foreach

       }

    }

}

 

public class Emailer    //这里的Emailer没有实现接口,其实这里是一个隐含的假设接口,

{

    public void Update(object sender,UserAccountArgs args) //这里在写Update方法的时候实际上就是实现

    {                                                //了上面委托定义的接口

       //...                                         //这里方法名可以任意,事件没有方法限制

       string toAddress = args.ToAddress;

    }

}

 

public class Mobile : IAccountObserver

{

    public void Update(UserAccountArgs args)

    {

       //...

       string mobileNumber = args.MobileNumber;

    }

}

 

class App

{

    public static void Main()

    {

       BankAccount bankAccount = new BankAccount();

      

       Emailer emailer = new Emailer();

      

       banAccount.AccountChange +=

           new AccountChangeEventHandler(emailer.Update);   // 背后就是实现Add

          

       //...

      

       bankAccount.Withdraw(234);

    }

}

 

只要delegate稳定下来,整个都会稳定,delegate可以把它充当接口来对象

接口只要:一稳定,二保证契约这个合同

源自:李建忠老师

抱歉!评论已关闭.