魔兽世界6.2 超远视角:observer模式感悟(目的是松耦合)——循序渐进让世界如此美妙

来源:百度文库 编辑:九乡新闻网 时间:2024/07/14 02:22:54

        不知不觉已经进入了设计模式璀璨的迷宫,早先偶然进入,it is so far that I can't understanding anthing .最近的项目应用和书上讲解的对比,昨天有偶然看到了李建忠老师的讲座,感觉自己开始真正成为了一个淘金者,而这条路的方向看似慢慢明朗起来。

       李建忠最鲜明的主张是,设计模式是一种结果,而不是要去套用的规则。所以讲座从我们最常规的思维开始,逐步演化,让循序渐进在此充发挥了他的作用。感受非常深刻!也很感动。

观察者模式的存在的必要:

一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。

动机:
依赖抽象,实现软件体系结构松耦合
手段:利用面向对象,形成稳定的依赖
原则:依赖倒置:具体细节依赖抽象,不稳定依赖稳定
意图:
得到一对多的依赖关系,当一个对象的状态发生改变,依赖他的对象得到统统自动更新
要点:
独立地改变(扩展、继承接口)目标和观察者
接口概念:1.稳定;2.表达了契约合同,不一定用Inerface表现

事件和observer模式的关系:
事件中所使用的程序接口(用委托来实现),
委托比接口更加松耦合
委托(约定)要求:参数类型和返回值类型一致就可以
接口要求:方法名称也必须相同
委托将一些功能实现了,例如add,用+=实现了;遍历,隐含实现了;

从紧耦合到松耦合的演化:(自然的未经设计模式的代码)

    

public class BandAccount

{
    Emailer emailer;
    Mobile mobile;

    public void withdraw(int data)
    {
        //...
        emailer.SendEmail(userEmail);
        mobile.SendNotification(phoneNumber);
    }
}
public class Emailer

{
  
  //希望通知到用户帐户emil

    //发送通知。让自己得到更新
    public void SendEmail(sting userEmail)//未将参数提取出来
    {
        //..
    }
}
public class Mobile

{

    //发送通知。让自己得到更新
    public void SendNotification(string phoneNumber) //未将参数提取出来
    {
        //..
    }
}

第一步:分化B

 

 public class UserAccountArgs //用户信息类,这个类的信息将用作参数传递,args将是一个数组
 {
  public string moble;
  public string email;
  public UserAccountArgs()
  {
  }
 }

public class BandAccount //A还没有分化
{
    //一对一依赖关系-------------------
    IAccountObserver emailer; //弱依赖关系
    public void Withdraw(int data)
    {
    //...

     UserAccountArgs args = new UserAccountArgs();//构造参数

    //...

        args.email = data // 此处将args的email属性赋值,没有这句,实现不了
        emailer.Update(args);
    }
}

 重要改进:
    Mobile mobile = new Mobile();
    Email email = new Email();

    public void withdraw(UserAccountArgs args)  //传递的是参数和接口相同,实现了真正的参数抽象化

    {
        mobile.Update(args);
        email.Update (args);
    }

//------------------------------------
public interface IAccountObserver
{
    void Update(UserAccountArgs args); //args中包含了用户信息,例如用户手机号,email地址

//提取出了方法和参数
}
public class Emailer : IAccountObserver
{
    //希望通知到用户帐户emil

    //发送通知。让自己得到更新
    public void Update(UserAccountArgs args) //将参数提取出来
    {
        //..
        string ToAddress = args.ToAddress; //参数具体传入
    }
}
public class Mobile : IAccountObserver
{

    //发送通知。让自己得到更新
    public void Update(UserAccountArgs args) //将参数提取出来
    {
        //..
        string mobileNumber = args.MobileNumber; //参数具体传入
    }
}

分化A

public abstract class Subject
{
    // ArrayList observerList = new ArrayList();  //泛型,接口封装,实现一对多

     ArrayList observerList = new ArrayList(); //此处的概念是可变长度的数组,.net中用这种写法

    protected virtual void Notify(UserAccoutArgs 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 BandAccount : Subject //  如果需要改变,就扩展
{
        public void Withdraw(UserAccountArgs args)
    {
    //...
          Notify(args);//对每一个对象进行更新
    }
}

--------------------------------------------------------------------------

 流程调用:

        UserAccountArgs args = new UserAccountArgs();//参数传入
        args.moble = "234";
        args .email = "wangshiying1971@163.com";
        BandAccount bankAccount = new BandAccount();
        bankAccount.withdraw(args);

实现了订阅功能(观察者模式)的流程调用

思路,加入了

  • 接口实例化到实现类
  • 订阅过程(用到了可变长度数组ArrayList 的概念,订阅过程,就是向数组传递参数的过程)

       UserAccountArgs args = new UserAccountArgs();  //参数传入
        args.moble = "234";
        args.email = "wangshiying1971@163.com";

 

        IAccountObserver mobile = new Mobile();//接口实例化到实现类
        IAccountObserver email = new Email();//接口实例化到实现类

       
        bankAccount.AddObserver(mobile);//将实现类加入到数组——订阅过程
        bankAccount.AddObserver(email);//将实现类加入到数组——订阅过程

 

        BandAccount bankAccount = new BandAccount();
        bankAccount.withdraw(args);


项目联想:工作中的那个用户对象,老板要加上身价等级。
分析:如果修改用户类,将会修改类的字段、属性、显示方法等。类似的改变今后还会有很多。
1.身价等级、2.用户自定义等级、3.约会等级这三个等级中,1和3对应,只是表现不同,1表现的是账户的余额-等级的对应关系,得到的结果是等级,3表现的是等级-花费金额,目的为了得到金额。
这三个需求,都是等级和金额对应关系这个对象的不同属性和方法。

与等级相关的类视图