个人对“观察者模式”的一些整理

本文通过一个生动的例子介绍了观察者模式的实现过程,从最初的简单实现到逐步改进,最终使用委托和事件来降低耦合度,详细展示了如何在.NET中实现观察者模式。

在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。

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

 

生活场景: 假设有个超女,有很多粉丝追求她,每次开发布会,说:“姐来了,快出来给我投票啊!我要发行新专辑了,要签名的都过来啊”;结果,一群粉丝都蜂拥而上,找她签名,满足追星的愿望。这样就形成了:超女——粉丝,关注和被关注的关系,在软件方面可以归为:观察者模式

终极目标:实现 召开招聘会就发消息给粉丝们。

第一种思路:我这水平的人的普遍想法

 

ExpandedBlockStart.gif 代码
  class  Program
    {
        
static   void  Main( string [] args)
        {
            Girl qqGril
= new  Girl();
            Boy haha1 
=   new  Boy( " haha " , qqGril);
             qqGril.Addboys(haha1);
             qqGril.SetMsg 
=   " 我要开发布会啦,想找我签名的快死过来! " ;
             qqGril.SendMsg();
            Console.ReadLine();
        }
    }
    
class  Girl
    {
        List
< Boy >  boyLs  =   new  List < Boy > (); // 泛型集合 装载 粉丝门
         public   void  Addboys(Boy sx)
        {
// 添加一个粉丝
            boyLs.Add(sx);
        }
        
public   void  Removeboys(Boy sx)
        {
// 看这家伙不爽 ,删除掉
            boyLs.Remove(sx);
        }
        
public   void  SendMsg()
        {
// 开发布会给粉丝们发消息
             foreach  (Boy b  in  boyLs)
            {
                b.ShowMsg();
            }
        }
        
///   <summary>
        
///  设置发送信息
        
///   </summary>
         private   string  _SetMsg;
        
public   string  SetMsg
        {
            
get  {  return  _SetMsg; }
            
set  { _SetMsg  =  value; }
        }
    }
    
class  Boy
    {
        
private   string  name;
        
private  Girl girl;
        
public  Boy( string  name, Girl girl)
        {
            
this .name  =  name;
            
this .girl  =  girl;
        }
        
public   void  ShowMsg()
        {
            Console.WriteLine(
" 美女发消息给:{0},{1} " , name, girl.SetMsg);
        }
    }

 

运行结果

 这样写不好的地方是耦合度太高,如果要发消息给电视台 还要在增加一个电视台的类,这样就需要提取重构

 

ExpandedBlockStart.gif 代码
class  Program
    {
        
static   void  Main( string [] args)
        {
            Girl qqGril
= new  Girl();
            Boy haha1 
=   new  Boy( " haha " , qqGril);
            CCTV cctv 
=   new  CCTV( " 电视台 " , qqGril);
             qqGril.Addboys(haha1);
             qqGril.Addboys(cctv);
             qqGril.SetMsg 
=   " 我要开发布会啦 " ;
             qqGril.SendMsg();
            Console.ReadLine();
        }
    }
    
class  Girl
    {
        List
< Observer >  boyLs  =   new  List < Observer > (); // 泛型集合 装载 粉丝门
         public   void  Addboys(Observer sx)
        {
// 添加一个粉丝
            boyLs.Add(sx);
        }
        
public   void  Removeboys(Observer sx)
        {
// 看这家伙不爽 ,删除掉
            boyLs.Remove(sx);
        }
        
public   void  SendMsg()
        {
// 开发布会给粉丝们发消息
             foreach  (Observer b  in  boyLs)
            {
                b.ShowMsg();
            }
        }
        
///   <summary>
        
///  设置发送信息
        
///   </summary>
         private   string  _SetMsg;
        
public   string  SetMsg
        {
            
get  {  return  _SetMsg; }
            
set  { _SetMsg  =  value; }
        }
    }
    
///   <summary>
    
///  观察者基类
    
///   </summary>
     abstract   class  Observer
    {
        
protected   string  name;
        
protected  Girl girl;
        
public  Observer( string  name, Girl girl)
        {
            
this .name  =  name;
            
this .girl  =  girl;
        }
        
public   abstract   void  ShowMsg(); // 虚方法
    }
    
class  Boy:Observer
    {
        
public  Boy( string  name, Girl girl)
            : 
base (name, girl)
        { }
        
public   override   void  ShowMsg()
        {
            Console.WriteLine(
" 美女发消息给:{0},{1},快来要签名 " ,name,girl.SetMsg);
        }
    }
    
class  CCTV : Observer
    {
        
public  CCTV( string  name, Girl girl)
            : 
base (name, girl)
        { }
        
public   override   void  ShowMsg()
        {
            Console.WriteLine(
" 美女发消息:{0},快来采访 " , girl.SetMsg);
        }
    }

 

结果如下:

但是只完成了一半,因为 超女毕竟也会老去,也不可能一直红下去,所以我们可能又去关注其它方面,比如,房价怎么还没降啊,物价又上涨了等等,这些都可以抽象为一个接口,然后让具体的被观察者去继承这个接口:

 

ExpandedBlockStart.gif 代码
  class  Program
    {
        
static   void  Main( string [] args)
        {
            Subject qqGril 
=   new  Girl();
            Boy haha1 
=   new  Boy( " haha " , qqGril);
            CCTV cctv 
=   new  CCTV( " 电视台 " , qqGril);
             qqGril.Addboys(haha1);
             qqGril.Addboys(cctv);
             qqGril.SetMsg 
=   " 我要开发布会啦 " ;
             qqGril.SendMsg();
            Console.ReadLine();
        }
    }
    
interface  Subject
    {
        
void  Addboys(Observer sx);
        
void  SendMsg();
        
string  SetMsg
        {
            
get ;
            
set ;
        }
    }
    
class  Girl : Subject
    {
        List
< Observer >  boyLs  =   new  List < Observer > (); // 泛型集合 装载 粉丝门
         public   void  Addboys(Observer sx)
        {
// 添加一个粉丝
            boyLs.Add(sx);
        }
        
public   void  Removeboys(Observer sx)
        {
// 看这家伙不爽 ,删除掉
            boyLs.Remove(sx);
        }
        
public   void  SendMsg()
        {
// 开发布会给粉丝们发消息
             foreach  (Observer b  in  boyLs)
            {
                b.ShowMsg();
            }
        }
        
///   <summary>
        
///  设置发送信息
        
///   </summary>
         private   string  _SetMsg;
        
public   string  SetMsg
        {
            
get  {  return  _SetMsg; }
            
set  { _SetMsg  =  value; }
        }
    }
    
///   <summary>
    
///  观察者基类
    
///   </summary>
     abstract   class  Observer
    {
        
protected   string  name;
        
protected  Subject girl;
        
public  Observer( string  name, Subject girl)
        {
            
this .name  =  name;
            
this .girl  =  girl;
        }
        
public   abstract   void  ShowMsg(); // 虚方法
    }
    
class  Boy:Observer
    {
        
public  Boy( string  name, Subject girl) // 这样的好处是:观察者观察的是 抽象的被观察着,这样就不局限在“超女”这一方面,可以是国家物价局,国家铁道部等等,只要实现了Subject接口
            :  base (name, girl)
        { }
        
public   override   void  ShowMsg()
        {
            Console.WriteLine(
" 美女发消息给:{0},{1},快来要签名 " ,name,girl.SetMsg);
        }
    }
    
class  CCTV : Observer
    {
        
public  CCTV( string  name, Subject girl)
            : 
base (name, girl)
        { }
        
public   override   void  ShowMsg()
        {
            Console.WriteLine(
" 美女发消息:{0},快来采访 " , girl.SetMsg);
        }
    }

 

 观察者模式:定义了一对多的关系,让多个观察者对象同时监听某一主题对象,这个主题对象在状态发生改变的时候就会通知所有观察对象,使他们能够自动更新自己。

虽然上面的观察者和被观察者都被抽象出来,但是还有问题:抽象通知者还是依赖抽象观察者,如果没有抽象观察者这个接口,就没法完成通知任务,而且并不是每个具体的观察方法都有ShowMsg()这个方法,所以还是有不足之处

委托和事件解决方法:

 

ExpandedBlockStart.gif 代码
class  Program
    {
        
static   void  Main( string [] args)
        {
            Girl qqGril 
=   new  Girl();
            Boy haha1 
=   new  Boy( " haha " , qqGril);
            CCTV cctv 
=   new  CCTV( " 电视台 " , qqGril);
            qqGril.SendAllMsg 
+=   new  EventHander(haha1.ShowBoyMsg);
            qqGril.SendAllMsg 
+=   new  EventHander(cctv.ShowCCTVMsg);
             qqGril.SendMsg();
            Console.ReadLine();
        }
    }
    
interface  Subject
    {
        
// void Addboys(Observer sx); // 抽象通知者由于不依赖抽象观察者,所以增加的方法也不要了
         void  SendMsg();
        
string  SetMsg
        {
            
get ;
            
set ;
        }
    }
    
delegate   void  EventHander(); // 声明一个无参数,无返回值的委托 EventHander
     class  Girl : Subject
    {
        
// List<Observer> boyLs = new List<Observer>();
        
// public void Addboys(Observer sx)
        
// { // 添加一个粉丝
        
//     boyLs.Add(sx);
        
// }
        
// public void Removeboys(Observer sx)
        
// { // 看这家伙不爽 ,删除掉
        
//     boyLs.Remove(sx);
        
// }
        
// public void SendMsg()
        
// { // 开发布会给粉丝们发消息
        
//     foreach (Observer b in boyLs)
        
//     {
        
//         b.ShowMsg();
        
//     }
        
// }
         public   event  EventHander SendAllMsg; // 声明一个 委托为 eventHander的事件
         public   void  SendMsg()
        {
// 开发布会给粉丝们发消息
             if  (SendAllMsg  !=   null )
                SendAllMsg();
        }
        
///   <summary>
        
///  设置发送信息
        
///   </summary>
         private   string  _SetMsg;
        
public   string  SetMsg
        {
            
get  {  return  _SetMsg; }
            
set  { _SetMsg  =  value; }
        }
    }
    
class  Boy 
    {
        
protected   string  name;
        
protected  Subject girl;
        
public  Boy( string  name, Subject girl)
        {
            
this .name  =  name;
            
this .girl  =  girl;
        }
        
public    void  ShowBoyMsg() // 修改方法名称为ShowBoyMsg
        {
            Console.WriteLine(
" 美女发消息给:{0},{1},快来要签名 " , name, girl.SetMsg);
        }
    }
    
class  CCTV 
    {
        
protected   string  name;
        
protected  Subject girl;
        
public  CCTV( string  name, Subject girl)
        {
            
this .name  =  name;
            
this .girl  =  girl;
        }
        
public    void  ShowCCTVMsg() /// /修改方法名称为ShowCCTVMsg
        {
            Console.WriteLine(
" 美女发消息:{0},快来采访 " , girl.SetMsg);
        }
    }

 这是在看完《大话设计模式》这本书后,根据里面的内容自己小结的,当然更具体的介绍还要去仔细阅读那本书,

 《大话设计模式》这本书真的很不错,特别推荐。当然自己也是菜鸟,今天工作不忙就整理了,也希望能提高自己

转载于:https://www.cnblogs.com/6303c/archive/2010/11/30/1892242.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值