|   登录   |   注册   |   设为首页   |   加入收藏   

用户登录

close

用户名:

密码:

新用户注册

close

用户名:

密码:

密码确认:

电子邮箱:

关注内容:

个人主页:

帮助

close

龙宇网成立于2008年3月,网站进入整体运作于2010年10月1日。

在这里,我们把它做成了一个真正意义上的网站,完全以个人的信息为内容,以网友的需要为主导,全力搜罗各种信息,建立完善的网站功能,使网友在这里可以第一时间找到所需要的信息。

现在,经过三年的努力,网站的资料已经相当丰富,而网站得到了大家的喜爱和认可。

但,我们还是会继续努力下去,让网间的这份快乐继续持续下去,让这份闲暇时的日子,与快乐一并同行。

寻觅快乐,网住快乐,关注网络,是龙宇网的宣言与承诺。

设计模式之观察者模式

分类: 系统架构 发布时间: 2013-01-30 22:57:25 浏览次数: 3496
内容提要: 观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

 

天气渐渐开始变暖和了,天天做办公室写代码感觉身体越来越差了,该活动活动了,跟快乐技术沙龙嗨皮吧秦春林交流后决定天气暖和了在群里发布一次小的户外活动,大家一起出去爬爬山或者运动运动,放松放松自己的身体和心情啊!嗨皮吧QQ群:190784175

          一、案例场景

           没错,按惯例上面就是今天设计模式的场景,那么我们来分析一下下面的场景吧:首先,我们此次户外活动的组织者是快乐技术沙龙嗨皮吧(命名为:HappyBar)。嗨皮吧负责维护所有参与的成员,并且通知成员活动的具体时间与集合的地点,并且成员需要观察嗨皮吧的通知来获得活动的消息。那么我们来用代码实现一把:

           1.快乐技术沙龙HappyBar的实现:

              ① 首先需要维护一个成员的集合,这个集合存放所有参加活动的成员,包括添加成员,如果有成员临时有事就需要从集合中移除,所以还需要一个移除成员。

              ② 接下来有一个发布通知的方法通知所有成员活动信息已经发布了。

              ③ 最后就是活动的详细信息、代码如下:

复制代码
 /// <summary>
    /// 嗨皮吧 春游计划
    
/// </summary>
    public class HappyBar
    {
        //维护QQ群报名参与活动的成员
        List<QQMember> memberList = new List<QQMember>();

        /// <summary>
        /// 增加参与活动的成员
        
/// </summary>
        /// <param name="member">参与活动的成员</param>
        public void Attach(QQMember member)
        {
            memberList.Add(member);
        }

        /// <summary>
        /// 移除活动的成员
        
/// </summary>
        /// <param name="member"></param>
        public void Detach(QQMember member)
        {
            memberList.Remove(member);
        }

        /// <summary>
        /// 发布活动的通知
        
/// </summary>
        public void Notify()
        {
            memberList.ForEach(p => p.GoDestination());
        }

        /// <summary>
        /// 活动发布的信息
        
/// </summary>
        public string PublishInfo
        {
            get;
            set;
        }
    }
复制代码

 

           2.  活动参与者成员Member的实现 

          ①参与人有自己的基本信息例如名字。

          ②参与人要读取活动的通知并且按时前往目的地,代码如下:

复制代码
 /// <summary>
    /// 嗨皮吧QQ群成员类
    
/// </summary>
    public class QQMember
    {
        //参与人姓名
        public string Name { getset; }
        //该参与人需要关注的通知来源
        public HappyBar happyBar { getset; }

        /// <summary>
        /// 实际行动,根据活动信息前往目的地
        
/// </summary>
        public void GoDestination()
        {
            Console.WriteLine("{0} 正在前往 {1}..",Name,happyBar.PublishInfo);
        }
    }
复制代码

         3.主函数调用代码如下:

复制代码
static void Main(string[] args)
        {
            //春游活动组织发起者
            HappyBar bar = new HappyBar();

            QQMember memberZhang = new QQMember() { Name="张智", happyBar = bar };
            QQMember memberDing = new QQMember() { Name="丁朝阳", happyBar = bar };
            QQMember memberZheng = new QQMember() { Name = "郑亚敏", happyBar = bar };

            bar.Attach(memberZhang); //张智参加活动
            bar.Attach(memberDing);  //丁朝阳参加活动
            bar.Attach(memberZheng); //郑亚敏参加互动

            bar.Detach(memberZhang); //张智临时有事,取消活动

            
//设置活动信息
            bar.PublishInfo = " 怀柔水长城 时间:2012年4月XX日";

            //发起活动及通知
            bar.Notify();
}
复制代码

          运行结果如下:

         

二、观察者模式

           上边的代码显然耦合度太高,如果这个时候我流程发起的组织不是嗨皮吧了呢? 是不是要重新加一个发起的类,并且修改成员关注通知的属性。在如果发起的活动不是指面对QQ群成员,还面对社区成员呢?是不是就需要加入一个社区成员的成员类,那么活动发起类的集合就需要重构了。观察者模式提供了一个很好的方案,即能扩展又能满足我们现有的需求。

          1. 观察者模式介绍

           观察者模式类图如下:

           

          ① Subject接口:抽象了主题类,这样将来不管是什么主题只要实现这个接口就可以发起主题活动。

          ② Observer接口:抽象了观察者类,不管是什么类型的观察者都可以通过实现观察者接口来具有观察主题通知的功能。

          ③ ConcreteSubject类:实现了主题抽象,实现具体的功能。对应我们上边的 HappyBar类,用来维护和发起活动通知。

          ④ ConreteObserver类:实现了观察者的抽象,实现具体功能。对应我们上边的QQMember类,用来观察主题类的通知,并更新自身的状态。

        2.重构我们的代码

         首先我们需要抽象出主题类的规则与观察者类,这样我们将来不管是什么主题和观察者,都可以通过实现各自定义抽象来扩展程序,从而避免了修改程序。代码如下:

复制代码
 public interface ISubject
    {
        //添加成员
        void Attach(IObserver member);
        //移除成员
        void Detach(IObserver member);
        //通知
        void Notify();
        string PublishInfo { get; set; }
    }

    public interface IObserver
    {
        //根据通知更新自己
        void GoUpdate();
    }
复制代码

        接下来我们需要将我们之前的主题类也就是活动发起类HappyBar做一些修改让自己实现ISubject接口,并修改成员集合的类型为抽象的IObserver接口类型,代码如下:

复制代码
 /// <summary>
    /// 嗨皮吧 春游计划
    
/// </summary>
    public class HappyBar : ISubject
    {
        //维护QQ群报名参与活动的成员
        List<IObserver> memberList = new List<IObserver>();

        /// <summary>
        /// 增加参与活动的成员
        
/// </summary>
        /// <param name="member">参与活动的成员</param>
        public void Attach(IObserver member)
        {
            memberList.Add(member);
        }

        /// <summary>
        /// 移除活动的成员
        
/// </summary>
        /// <param name="member"></param>
        public void Detach(IObserver member)
        {
            memberList.Remove(member);
        }

        /// <summary>
        /// 发布活动的通知
        
/// </summary>
        public void Notify()
        {
            memberList.ForEach(p => p.GoUpdate());
        }

        /// <summary>
        /// 活动发布的信息
        
/// </summary>
        public string PublishInfo
        {
            get;
            set;
        }
    }
复制代码

        继续重构成员类的实现,一样实现成员类的接口即可。代码如下:

复制代码
 /// <summary>
    /// 嗨皮吧QQ群成员类
    
/// </summary>
    public class QQMember : IObserver
    {
        //参与人姓名
        public string Name { getset; }
        //该参与人需要关注的通知来源
        public HappyBar happyBar { getset; }

        /// <summary>
        /// 实际行动,根据活动信息前往目的地
        
/// </summary>
        public void GoUpdate()
        {
            Console.WriteLine("{0} 正在前往 {1}..",Name,happyBar.PublishInfo);
        }
    }
复制代码

        主函数调用如下:

复制代码
   //春游活动组织发起者
            HappyBar bar = new HappyBar();

            IObserver memberZhang = new QQMember() { Name="张智", happyBar = bar };
            IObserver memberDing = new QQMember() { Name = "丁朝阳", happyBar = bar };
            IObserver memberZheng = new QQMember() { Name = "郑亚敏", happyBar = bar };

            bar.Attach(memberZhang); //张智参加活动
            bar.Attach(memberDing);  //丁朝阳参加活动
            bar.Attach(memberZheng); //郑亚敏参加互动

            bar.Detach(memberZhang); //张智临时有事,取消活动

            
//设置活动信息
            bar.PublishInfo = " 怀柔水长城 时间:2012年4月XX日";

            //发起活动及通知
            bar.Notify();
复制代码

         3.程序的扩展

          这时我们如果想要新增一个主题发起者不是嗨皮吧,而是参加Windows Phone7 与 Windows8开发者训练营的主题,发起者是微软。我们扩展的代码如下:

复制代码
 public class MicrosoftCenter : ISubject
    {
        List<IObserver> memberList = new List<IObserver>();

        /// <summary>
        /// 增加参与活动的成员
        
/// </summary>
        /// <param name="member">参与活动的成员</param>
        public void Attach(IObserver member)
        {
            memberList.Add(member);
        }

        /// <summary>
        /// 移除活动的成员
        
/// </summary>
        /// <param name="member"></param>
        public void Detach(IObserver member)
        {
            memberList.Remove(member);
        }

        /// <summary>
        /// 发布活动的通知
        
/// </summary>
        public void Notify()
        {
            memberList.ForEach(p => p.GoUpdate());
        }

        /// <summary>
        /// 活动发布的信息
        
/// </summary>
        public string PublishInfo
        {
            get;
            set;
        }
    }
复制代码

        当然可以参与的成员有,开发者、学生、老板等等类型的观察者,我们只要将不同类型的观察者类型实现对应的观察者抽象即可,代码如下:

复制代码
   /// <summary>
    /// 开发者
    
/// </summary>
    public class Developer : IObserver
    {   
        //参与人姓名
        public string Name { getset; }
        //该参与人需要关注的通知来源
        public ISubject subject { getset; }

        /// <summary>
        /// 实际行动,根据活动信息前往目的地
        
/// </summary>
        public void GoUpdate()
        {
            Console.WriteLine("{0} 正在前往 {1}..", Name, subject.PublishInfo);
        }
    }

    /// <summary>
    /// 学生
    
/// </summary>
    public class Student : IObserver
    {
        //参与人姓名
        public string Name { getset; }
        //该参与人需要关注的通知来源
        public ISubject subject { getset; }

        /// <summary>
        /// 实际行动,根据活动信息前往目的地
        
/// </summary>
        public void GoUpdate()
        {
            Console.WriteLine("{0} 正在前往 {1}..", Name, subject.PublishInfo);
        }
    }
复制代码

 

       主函数调用如下:

复制代码
   static void Main(string[] args)
        {
            //微软开发者训练营
            MicrosoftCenter mc = new MicrosoftCenter();

            IObserver member1 = new Developer() { Name = "张三", happyBar = mc };
            IObserver member2 = new Developer() { Name = "李四", happyBar = mc };

            mc.Attach(member1);
            mc.Attach(member2);
            mc.PublishInfo = "微软望京开发者训练营";
            mc.Notify();
}
复制代码

       运行结果如下:

     

          三、C#版观察者模式

           理解了观察者模式这种通知机制后,我们能感觉到,就是当发起通知时去调用通知所有成员。这类似于C#中的委托,如果该场景在C#中应用,使用委托可以更灵活方便,代码不一定非要模式,简单就是美!使用委托重构方法如下:

           1.声明一个通知更新的委托:

 //定义委托
    delegate void EventHandler();

          2.定义春游活动主题:

复制代码
 /// <summary>
    /// 嗨皮吧 春游计划
    
/// </summary>
    public class HappyBar 
    {
        //定义一个事件,当发布活动的时候触发
        public event EventHandler GoUpdate;

        /// <summary>
        /// 发布活动的通知
        
/// </summary>
        public void Notify()
        {
            GoUpdate();
        }

        /// <summary>
        /// 活动发布的信息
        
/// </summary>
        public string PublishInfo
        {
            get;
            set;
        }
    }
复制代码

         3.定义参与者(观察者)成员

复制代码
/// <summary>
    /// 嗨皮吧QQ群成员类
    
/// </summary>
    public class QQMember 
    {
        //参与人姓名
        public string Name { getset; }
        //该参与人需要关注的通知来源
        public HappyBar happyBar { getset; }

        /// <summary>
        /// 实际行动,根据活动信息前往目的地
        
/// </summary>
        public void GoUpdate()
        {
            Console.WriteLine("{0} 正在前往 {1}..", Name, happyBar.PublishInfo);
        }
    }
复制代码

            4.主函数调用如下:

复制代码
  static void Main(string[] args)
        {
            HappyBar hb = new HappyBar();

            QQMember member1 = new QQMember() { Name = "张三", happyBar = hb };
            QQMember member2 = new QQMember() { Name = "李四", happyBar = hb };
            hb.PublishInfo = " 怀柔水长城 时间:2012年4月XX日";
            hb.GoUpdate += new 观察者模式1.EventHandler(member1.GoToUpdate);
            hb.GoUpdate += new 观察者模式1.EventHandler(member2.GoToUpdate);

            hb.Notify();
}
复制代码

           5.运行结果如下:

  

       观察者模式结束啦,户外活动具体时间还没有确定,使用委托事件的代码现在还是处于高耦合的状态,如何解耦就看大家啦,可以把代码以留言的形式跟大家分享!~ 呵呵,顺便给个推荐吧!写的很辛苦啊!

1
1

分类: 系统架构   |   评论: 0   |   引用: 0   |   浏览次数: 3496