第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

时间: 2024-10-10 18:34:48

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

观察者模式(Observer Pattern) 详解

观察者模式(Observer Pattern): 定义了对象之间的一对多的依赖, 这样一来, 当一个对象改变状态时, 它的所有依赖者都会收到通知并自动更新. 使用方法: 1. 首先新建主题(subject)接口, 负责注册(register)\删除(remove)\通知(notify)观察者; 观察者(observer)接口, 负责更新(update)数据; 主题(subject)接口: 注册观察者(registerObserver), 删除观察者(removeObserver), 通知观察者(

《Swift开发实战》——第16章,第16.1节下标脚本语法

第16章 下标脚本 Swift开发实战 在Swift语言中,类(class).结构体(structure)和枚举(enumeration)等目标中定义下标脚本,被认为是访问对象.集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法.在本章的内容中,将详细讲解Swift下标脚本的基本知识. 16.1 下标脚本语法 在Swift语言中,可以使用下标脚本访问一个数组(Array)实例中的元素,参见如下所示的格式. someArray[index] 在访问字典(Dictionary)实例中的元素

求大神解答一下-C++ primer plus 第6版 中文版 第16章复习题的一个问题

问题描述 C++ primer plus 第6版 中文版 第16章复习题的一个问题 奇葩的是课后居然没答案...... 求正规.严谨.简洁的标准答案! 程序清单16.15(在p708页):functor.cpp //functor.cpp--using a functor #include尖括号iostream尖括号 #include尖括号list尖括号 #include尖括号iterator尖括号 #include尖括号algorithm尖括号 template//functor class

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

原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:webabcd 介绍 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例 有一个Message实体类,某些对象对它的操作有Insert()方法,当发生某些改变的时候,通知所有这些对象并执行Insert()方法. MessageModel using

观察者模式(Observer Pattern) Java内置使用方法

Java内置的观察者模式, 是通过继承父类, 实现观察者模式的几个主要函数: Observerable(可被观察的): 是一个父类(class),addObserver(), 添加观察者; deleteObserver(), 删除观察者; notifyObservers(), 通知观察者;setChanged(), 确认更改; Observer(观察者): 是一个接口(interface), update(), 更新观察者数据; setChanged()->notifyObservers(),

[叩响C#之门]第16章 委托和事件 16.4 事件处理机制

16.4 事件处理机制 16.4.1 事件处理机制的原理 我们已经知道,Windows应用程序是需要事件驱动的,当一个窗体应用程序启动后,系统就不停的检测是否有事件发生,如果检测到事件,就执行对应的事件处理程序.

《Swift开发实战》——第16章,第16.3节下标脚本选项

16.3 下标脚本选项 在Swift语言中,下标脚本允许任意数量的入参索引,并且每个入参类型也没有限制.下标脚本的返回值也可以是任何类型,下标脚本可以使用变量参数和可变参数.但是如果使用写入读出(in-out)参数或给参数设置默认值,这些操作都是不允许的. 在Swift语言中,可以在一个类或结构体中根据自身需要提供多个下标脚本实现.在定义下标脚本时通过入参个类型进行区分,使用下标脚本时会自动匹配合适的下标脚本实现运行,这就是下标脚本的重载. 在Swift程序中,一个下标脚本入参是最常见的情况,但

《Swift开发实战》——第16章,第16.2节下标脚本用法

16.2 下标脚本用法 在Swift语言中,根据使用场景的不同,下标脚本也具有不同的含义.通常下标脚本是用来访问集合(collection).列表(list)或序列(sequence)中元素的快捷方式.开发者可以在自己特定的类或结构体中,灵活地实现下标脚本来提供合适的功能. 例如,Swift 的字典(Dictionary)实现了通过下标脚本来对其实例中存放的值进行存取操作.在下标脚本中使用和字典索引相同类型的值,并且把一个字典值类型的值赋值给这个下标脚本来为字典设值.参见如下所示的演示代码. v

第 16 章 信息安全

SQL注入,OS命令注入,缓冲溢出.跨站脚本.缺少验证.缺少认证.使用硬编码证书.敏感数据忘记加密.不受限制上传文件类型.依赖不可信的输入.用不必要的高级权限执行任务.跨站请求伪造.... 16.1. CSRF(Cross-site request forgery)跨站请求伪造 CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF 原文出处:Netkiller