原文  第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

第16章 观察者模式(Oberver Pattern)的更多相关文章

  1. 第 16 章 观察者模式【Observer Pattern】

    以下内容出自:<<24种设计模式介绍与6大设计原则>> <孙子兵法>有云:“知彼知己,百战不殆:不知彼而知己,一胜一负:不知彼,不知己,每战必殆”,那怎么才能知己知 ...

  2. 第16章 List集合的总结和遍历

    第16章 List集合的总结和遍历 1.重构设计 根据Vector类,ArrayList类,和LinkedList类所具有的存储特点以及拥有的方法入手,发现共性往上抽取. 共同特点: 1.允许元素重复 ...

  3. ASM:《X86汇编语言-从实模式到保护模式》第16章:Intel处理器的分页机制和动态页面分配

    第16章讲的是分页机制和动态页面分配的问题,说实话这个一开始接触是会把人绕晕的,但是这个的确太重要了,有了分页机制内存管理就变得很简单,而且能直接实现平坦模式. ★PART1:Intel X86基础分 ...

  4. LPTHW 笨方法学习python 16章

    根据16章的内容作了一些扩展. 比如,判断文件如果存在,就在文件后追加,如不存在则创建. 同时借鉴了shell命令中类似 cat <<EOF > test的方法,提示用户输入一个结尾 ...

  5. java JDK8 学习笔记——第16章 整合数据库

    第十六章 整合数据库 16.1 JDBC入门 16.1.1 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API中的接口会有数据库厂商操作,称为JDBC驱动程 ...

  6. Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统 nsswitch.conf配置文件

    Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统  nsswitch.conf配置文件 朋友们,今天我对你们说,在此时此刻,我们虽然遭受种种困难和挫折,我仍然有一个梦 ...

  7. 《深入Java虚拟机学习笔记》- 第16章 控制流

    <深入Java虚拟机学习笔记>- 第16章 控制流

  8. 设计模式 - 观察者模式(Observer Pattern) 详细说明

    观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...

  9. 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

    原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...

随机推荐

  1. How to fix Column 'InvariantName' is constrained to be unique 解决办法!

    Introduction When you build a web project that uses Enterprise Library Community for the Application ...

  2. POJ 2586:Y2K Accounting Bug(贪心)

    Y2K Accounting Bug Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10024 Accepted: 4990 D ...

  3. 返璞归真 asp.net mvc (3) - Controller/Action

    原文:返璞归真 asp.net mvc (3) - Controller/Action [索引页] [源码下载] 返璞归真 asp.net mvc (3) - Controller/Action 作者 ...

  4. Redis 的性能

    Redis 的性能幻想与残酷现实 2011 年,当初选择 Redis 作为主要的内存数据存储,主要吸引我的是它提供多样的基础数据结构可以很方便的实现业务需求.另一方面又比较担心它的性能是否足以支撑,毕 ...

  5. System.Threading.ThreadStateException

    异常:"System.Threading.ThreadStateException"在未处理的异常类型 System.Windows.Forms.dll 发生 其它信息: 在能够调 ...

  6. 【SEO 决胜网络索引】 课程大纲及第一部分第一课:网络营销战略中的索引

    内容简介 1.课程大纲 2.第一部分第一课: 网络营销战略中的索引 3.第一部分第二课预告: 索引是什么 课程大纲 现在是网络为王的时代,人们越来越离不开互联网: SEO(Search Engine ...

  7. 未能加载文件或程序集“Common”或它的某一个依赖项。试图加载格式不正确的程序

    原因:操作系统是64位的,但发布的程序引用了一些32位的ddl,所以出现了兼容性的问题解决方案一:如果是64位机器,IIS——应用程序池——高级设置——启用32位应用程序 :true.解决方案二:修改 ...

  8. 面向服务的架构(SOA)

    SOA架构基础概念 面向服务的架构(SOA) 在深入探讨什么是面向服务的架构(SOA)之前,先建立一些基本的概念和术语的基本描述而非严格定义,所以也许有些定义在业内还存留争议,此处暂且忽略. 架构基础 ...

  9. IIS安装asp组件:JMail 邮件收发组件

    JMail简介 jmail是一种服务器端的邮件发送组件,和个人用的客户端邮件软件不一样的.jmail是在服务器上给程序用来发邮件用的,除了软件编程人员,其他人一般平常用不上. jmail是一个第三方邮 ...

  10. Twitter 新一代流处理工具——Heron 该纸币Storm Limitations

    Twitter 新一代流处理工具--Heron 该纸币Storm Limitations (空格分隔): Streaming-Processing Storm Problems scalability ...