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

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

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

 

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

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

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

 

代码
 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);
        }
    }

 

运行结果

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

 

代码
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);
        }
    }

 

结果如下:

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

 

代码
 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()这个方法,所以还是有不足之处

委托和事件解决方法:

 

代码
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);
        }
    }

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

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

posted @ 2010-11-30 17:19  aspc  阅读(301)  评论(0编辑  收藏  举报