第16章 观察者模式(Oberver Pattern)

原文  第16章 观察者模式(Oberver Pattern)

观察者模式

 

   概述:

 

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

        定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[GOF 《设计模式》]

 

  结构图:

 

 

   举例:商品竞拍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
     /// <summary>
     /// 竞价平台
     /// </summary>
    public  class  Platform
    {
        private  string  _name;
        public  Platform( string  name)
        {
            _name = name;
        }
        public  void  SendMeg(Goods good)
        {
            Console.WriteLine( "{0}出价{1}" ,_name,good.Price);
        }
    }
 
    public  class  Goods
    {
        public  Platform plat;
        //价格
        public  int  Price
        {
            get ;
            set ;
        }
        //出价
        public  void  Send()
        {
            plat.SendMeg( this );
        }
 
 
    }
    //client
     class  Program
     {
         static  void  Main( string [] args)
         {
             Platform p =  new  Platform( "A" );
             Goods g =  new  Goods();
             g.plat = p;
             g.Price = 1000;
             g.Send();
             Console.ReadLine();
         }
     }

上面这段代码是没有什么问题的,也实现了我们需要的功能,但是在Goods跟Platform之间进行了相互的方法及属性调用,形成了一个双向依赖的关系,这样假如其中一个变化,另一个也会发生变化。假设我们增加一个微信平台竞拍

1
2
3
4
5
6
7
8
9
10
11
12
13
    public  class  WeiXin
    {
        private  string  _name;
        public  WeiXin( string  name)
        {
            _name = name;
        }
        public  void  SendMeg(Goods good)
        {
            Console.WriteLine( "{0}出价{1}" ,_name,good.Price);
        }
 
    }

那我们的Goods类也得做修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public  class  Goods
    {
        public  Platform plat;
        public  WeiXin wx;
        //价格
        public  int  Price
        {
            get ;
            set ;
        }
        //出价
        public  void  Send()
        {
            plat.SendMeg( this );
            wx.SendMeg( this );
        }
 
    }

 

很显然,这样的设计违反了“开放封闭”原则,仅仅是增加了一个平台就需要我们改动Goods类,这不不是我们想要的效果,同时这个样的设计是比较糟糕的。我们在做进一步的处理。对变化进行封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
     /// <summary>
     /// 抽象类
     /// </summary>
     public  interface  ISend
     {
         void  SendMeg(Goods good);
     }
     /// <summary>
     /// 竞价平台
     /// </summary>
     public  class  Platform : ISend
    {
        private  string  _name;
        public  Platform( string  name)
        {
            _name = name;
        }
        public  void  SendMeg(Goods good)
        {
            Console.WriteLine( "{0}出价{1}" ,_name,good.Price);
        }
    }
 
    public  class  WeiXin : ISend
    {
        private  string  _name;
        public  WeiXin( string  name)
        {
            _name = name;
        }
        public  void  SendMeg(Goods good)
        {
            Console.WriteLine( "{0}出价{1}" ,_name,good.Price);
        }
 
    }
 
    public  class  Goods
    {
        public  ISend s;
      
        //价格
        public  int  Price
        {
            get ;
            set ;
        }
        //出价
        public  void  Send()
        {
            s.SendMeg( this );
        
        }
 
    }

 

我们让Goods里面的依赖Isend,我们已经弱化了对单个平台的依赖,这算是成功了第一步。但是我们要是增加平台,我们依然要改动Goods类,我们子在做进一步的封装。修改Goods类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
     public  class  Goods
     {
         public  List<ISend> list =  new  List<ISend>();
         public  void  Add(ISend s)
         {
             list.Add(s);
         }
         //价格
         public  int  Price
         {
             get ;
             set ;
         }
         //出价
         public  void  Send()
         {
             foreach  (var item  in  list)
             {
                 item.SendMeg( this );
             }
 
 
         }
 
     }

客户端调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
     class  Program
     {
         static  void  Main( string [] args)
         {
             Platform p =  new  Platform( "A" );
             WeiXin wx =  new  WeiXin( "B" );
             Goods g =  new  Goods();
             g.Add(p);
             g.Add(wx);
             g.Price = 1000;
             g.Send();
             Console.ReadLine();
         }
     }

到了这一步,我们基本上已经解决了大部分的问题了,但是我们还有一个小小的问题,就是平台需要依赖具体的Goods(商品),假如我们有多个商品呢?那还需要改平台类,所以我们在对Goods类进行封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    //竞拍
     /// <summary>
     /// 抽象类
     /// </summary>
     public  interface  ISend
     {
         void  SendMeg(Obj good);
     }
     /// <summary>
     /// 竞价平台
     /// </summary>
     public  class  Platform : ISend
     {
         private  string  _name;
         public  Platform( string  name)
         {
             _name = name;
         }
         public  void  SendMeg(Obj good)
         {
             Console.WriteLine( "{0}出价{1}" , _name, good.Price);
         }
     }
     /// <summary>
     /// 微信平台
     /// </summary>
     public  class  WeiXin : ISend
     {
         private  string  _name;
         public  WeiXin( string  name)
         {
             _name = name;
         }
         public  void  SendMeg(Obj good)
         {
             Console.WriteLine( "{0}出价{1}" , _name, good.Price);
         }
 
 
 
     }
     /// <summary>
     /// 任何东西
     /// </summary>
     public  abstract  class  Obj
     {
         public  List<ISend> list =  new  List<ISend>();
         //价格
         public  int  _price;
 
         public  Obj( int  price)
         {
             _price = price;
         }
         public  int  Price
         {
             get  return  _price; }
 
         }
         public  void  Add(ISend s)
         {
             list.Add(s);
         }
 
         //出价
         public  void  Send()
         {
             foreach  (var item  in  list)
             {
                 item.SendMeg( this );
             }
         }
     }
     /// <summary>
     /// 具体的商品
     /// </summary>
     public  class  Goods : Obj
     {
         public  Goods( int  price)
             base (price)
         { }
 
     }

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
13
     class  Program
     {
         static  void  Main( string [] args)
         {
             Platform p =  new  Platform( "A" );
             WeiXin wx =  new  WeiXin( "B" );
             Obj g =  new  Goods(1000);
             g.Add(p);
             g.Add(wx);
             g.Send();
             Console.ReadLine();
         }
     }

 

      实现效果

 

 

        1.使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达到松耦合。

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

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

 

        适用场景:

 

 

        1.当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

         2.当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。

         3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

 

     设计模式系列文章入口:http://www.diyibk.com/post/39.html

posted on 2014-05-10 18:36 NET未来之路 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/3720840.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值