第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.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
第16章 观察者模式(Oberver Pattern)的更多相关文章
- 第 16 章 观察者模式【Observer Pattern】
以下内容出自:<<24种设计模式介绍与6大设计原则>> <孙子兵法>有云:“知彼知己,百战不殆:不知彼而知己,一胜一负:不知彼,不知己,每战必殆”,那怎么才能知己知 ...
- 第16章 List集合的总结和遍历
第16章 List集合的总结和遍历 1.重构设计 根据Vector类,ArrayList类,和LinkedList类所具有的存储特点以及拥有的方法入手,发现共性往上抽取. 共同特点: 1.允许元素重复 ...
- ASM:《X86汇编语言-从实模式到保护模式》第16章:Intel处理器的分页机制和动态页面分配
第16章讲的是分页机制和动态页面分配的问题,说实话这个一开始接触是会把人绕晕的,但是这个的确太重要了,有了分页机制内存管理就变得很简单,而且能直接实现平坦模式. ★PART1:Intel X86基础分 ...
- LPTHW 笨方法学习python 16章
根据16章的内容作了一些扩展. 比如,判断文件如果存在,就在文件后追加,如不存在则创建. 同时借鉴了shell命令中类似 cat <<EOF > test的方法,提示用户输入一个结尾 ...
- java JDK8 学习笔记——第16章 整合数据库
第十六章 整合数据库 16.1 JDBC入门 16.1.1 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API中的接口会有数据库厂商操作,称为JDBC驱动程 ...
- Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统 nsswitch.conf配置文件
Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统 nsswitch.conf配置文件 朋友们,今天我对你们说,在此时此刻,我们虽然遭受种种困难和挫折,我仍然有一个梦 ...
- 《深入Java虚拟机学习笔记》- 第16章 控制流
<深入Java虚拟机学习笔记>- 第16章 控制流
- 设计模式 - 观察者模式(Observer Pattern) 详细说明
观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
随机推荐
- 顺序容器的insert使用方法
#include <iostream> #include <algorithm> #include <vector> #include <string> ...
- HTML5实际和离线应用分析
当前离线Web申请书,即,该装置不能访问因特网时的应用的执行.HTML5离线应用重点,主要开发人员希望.步骤离线应用开发有:首先我们应该知道设备是否可以连接;然后,它也应该可以访问某些资源(像.CSS ...
- Directx11学习笔记【三】 第一个D3D11程序
在先前的解决方案中新建一个新的Win32项目FirstD3D11Demo.在写代码之前,我们必须先添加dx11所需要的库.为了链接dx库,右键项目选择属性->vc++目录,在包含目录中添加你所安 ...
- Node.js Tools for Visual Studio
https://www.visualstudio.com/en-us/features/node-js-vs.aspx
- Atitit.软件GUIbutton和仪表板(01)--警报系统--
Atitit.软件GUIbutton和仪表板(01)--警报系统-- 1. 温度报警防区(鲁大师,360taskman) 1 2. os-区-----cpu_mem_io资源占用监測 1 3. Vm区 ...
- 说说PHP的autoLoad自动加载机制
__autoload的使用方法1: 最经常使用的就是这种方法,根据类名,找出类文件,然后require_one 复制代码 代码如下:function __autoload($class_name) { ...
- 创建在SQLServer 和 Oracle的 DBLINK
dblink 当我们要跨本地数据库.訪问另外一个数据库表中的数据时,本地数据库中就必需要创建远程数据库的dblink,通过dblink本地数据库能够像訪问本地数据库一样訪问远程数据库表中的数据. 一 ...
- Codeforces 442B Andrey and Problem(贪婪)
题目链接:Codeforces 442B Andrey and Problem 题目大意:Andrey有一个问题,想要朋友们为自己出一道题,如今他有n个朋友.每一个朋友想出题目的概率为pi,可是他能够 ...
- MySQL之终端(Terminal)管理MySQL
原文:MySQL之终端(Terminal)管理MySQL 前言:MySQL有很多的可视化管理工具,比如“mysql-workbench”和“sequel-pro-”. 现在我写MySQL的终端命令操作 ...
- Play Framework + ReactiveMongo
Play Framework + ReactiveMongo Play!是一个full-stack(全栈的)Java/Scala Web应用框架,包括一个简单的无状态MVC模型,具有Hibernate ...