原文:C#设计模式之十六不雅察看者模式(Observer Pattern)【行为型】
一、引言
今天是2017年11月份的最后一天,也就是2017年11月30日,操作今天再写一个模式,争取下个月(也就是12月份)把所有的模式写完,2018年,新的一年写一些新的对象。今天我们开始讲“行为型”设计模式的第四个模式,该模式是【不雅察看者模式】,英文名称是:Observer Pattern。还是老套路,先从名字上来看看。“不雅察看者模式”我第一次看到这个名称,我的理解是,既然有“不雅察看者”,那必定就有“被不雅察看者”了,“不雅察看者”监视着“被不雅察看者”,如果“被不雅察看者”有所步履,“不雅察看者”就会做出相应的行动来回应,哈哈,听起来是不是有点像“谍战”的味道。我所说的谍战不是天朝内的那种,好比:手撕鬼子,我说的是“谍影重重”的那类优秀影片,大家分明。“不雅察看者模式”在现实生活中,实例其实是很多的,好比:八九十年代我们订阅的报纸,我们会按期收到报纸,因为我们订阅了。银行可以给储户发手机短信,也是“不雅察看者模式”很好的使用的例子,因为我们订阅了银行的短信业务,当我们账户余额产生变革就会收到通知,还有很多,我就不一一列举了,阐扬大家的想象吧。好了,接下来,就让我们看看该模式具体是怎么实现的吧。
二、不雅察看者模式的详细介绍
2.1、动机(Motivate)
在软件构建过程中,我们需要为某些东西成立一种“通知依赖关系”——一个东西(方针东西)的状态产生转变,所有的依赖东西(不雅察看者东西)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵制变革。
使用面向东西技术,可以将这种依赖关系弱化,并形成一种不变的依赖关系。从而实现软件体系布局的松耦合。
2.2、意图(Intent)
界说东西间的一种一对多的依赖关系,以方便一个东西的状态产生转变时,,所有依赖于它的东西都得到通知并自动更新。 ——《设计模式》GoF
2.3、布局图
2.4、模式的构成
可以看出,在不雅察看者模式的布局图有以下角色:
(1)、抽象主题角色(Subject):抽象主题把所有不雅察看者东西的引用生存在一个列表中,并供给增加和删除不雅察看者东西的操纵,抽象主题角色又叫做抽象被不雅察看者角色,一般由抽象类或接口实现。
(2)、抽象不雅察看者角色(Observer):为所有具体不雅察看者界说一个接口,在得到主题通知时更新本身,一般由抽象类或接口实现。
(3)、具体主题角色(ConcreteSubject):实现抽象主题接口,具体主题角色又叫做具体被不雅察看者角色。
(4)、具体不雅察看者角色(ConcreteObserver):实现抽象不雅察看者角色所要求的接口,以便使自身状态与主题的状态相协调。
2.5、不雅察看者模式的代码实现
不雅察看者模式在显示生活中也有类似的例子,好比:我们订阅银行短信业务,当我们账户产生转变,我们就会收到相应的短信。类似的还有微信订阅号,今天我们就以银行给我发送短信当我们账户余额产生变革的时候为例来讲讲不雅察看者模式的实现,很简单,现实生活正例子也很多,理解起来也很容易。我们看代码吧,实现代码如下:
1 namespace 不雅察看者模式的实现 2 { 3 //银行短信系统抽象接口,是被不雅察看者--该类型相当于抽象主体角色Subject 4 public abstract class BankMessageSystem 5 { 6 protected IList<Depositor> observers; 7 8 //结构函数初始化不雅察看者列表实例 9 protected BankMessageSystem() 10 { 11 observers = new List<Depositor>(); 12 } 13 14 //增加预约储户 15 public abstract void Add(Depositor depositor); 16 17 //删除预约储户 18 public abstract void Delete(Depositor depositor); 19 20 //通知储户 21 public void Notify() 22 { 23 foreach (Depositor depositor in observers) 24 { 25 if (depositor.AccountIsChanged) 26 { 27 depositor.Update(depositor.Balance, depositor.OperationDateTime); 28 //账户产生了变革,并且通知了,储户的账户就认为没有变革 29 depositor.AccountIsChanged = false; 30 } 31 } 32 } 33 } 34 35 //北京银行短信系统,是被不雅察看者--该类型相当于具体主体角色ConcreteSubject 36 public sealed class BeiJingBankMessageSystem : BankMessageSystem 37 { 38 //增加预约储户 39 public override void Add(Depositor depositor) 40 { 41 //应该先判断该用户是否存在,存在不操纵,不存在则增加到储户列表中,这里简化了 42 observers.Add(depositor); 43 } 44 45 //删除预约储户 46 public override void Delete(Depositor depositor) 47 { 48 //应该先判断该用户是否存在,存在则删除,不存在无操纵,这里简化了 49 observers.Remove(depositor); 50 } 51 } 52 53 //储户的抽象接口--相当于抽象不雅察看者角色(Observer) 54 public abstract class Depositor 55 { 56 //状态数据 57 private string _name; 58 private int _balance; 59 private int _total; 60 private bool _isChanged; 61 62 //初始化状态数据 63 protected Depositor(string name, int total) 64 { 65 this._name = name; 66 this._balance = total;//存款总额即是余额 67 this._isChanged = false;//账户未产生变革 68 } 69 70 //储户的名称,假设可以独一区另外 71 public string Name 72 { 73 get { return _name; } 74 private set { this._name = value; } 75 } 76 77 public int Balance 78 { 79 get { return this._balance; } 80 } 81 82 //取钱 83 public void GetMoney(int num) 84 { 85 if (num <= this._balance && num > 0) 86 { 87 this._balance = this._balance - num; 88 this._isChanged = true; 89 OperationDateTime = DateTime.Now; 90 } 91 } 92 93 //账户操纵时间 94 public DateTime OperationDateTime { get; set; } 95 96 //账户是否产生变革 97 public bool AccountIsChanged 98 { 99 get { return this._isChanged; } 100 set { this._isChanged = value; } 101 } 102 103 //更新储户状态 104 public abstract void Update(int currentBalance, DateTime dateTime); 105 } 106 107 //北京的具体储户--相当于具体不雅察看者角色ConcreteObserver 108 public sealed class BeiJingDepositor : Depositor 109 { 110 public BeiJingDepositor(string name, int total) : base(name, total) { } 111 112 public override void Update(int currentBalance, DateTime dateTime) 113 { 114 Console.WriteLine(Name + ":账户产生了变革,变革时间是" + dateTime.ToString() + ",当前余额是" + currentBalance.ToString()); 115 } 116 } 117 118 119 // 客户端(Client) 120 class Program 121 { 122 static void Main(string[] args) 123 { 124 //我们有了三位储户,都是武林妙手,也对照有钱 125 Depositor huangFeiHong = new BeiJingDepositor("黄飞鸿", 3000); 126 Depositor fangShiYu = new BeiJingDepositor("方世玉", 1300); 127 Depositor hongXiGuan = new BeiJingDepositor("洪熙官", 2500); 128 129 BankMessageSystem beijingBank = new BeiJingBankMessageSystem(); 130 //这三位开始订阅银行短信业务 131 beijingBank.Add(huangFeiHong); 132 beijingBank.Add(fangShiYu); 133 beijingBank.Add(hongXiGuan); 134 135 //黄飞鸿取100块钱 136 huangFeiHong.GetMoney(100); 137 beijingBank.Notify(); 138 139 //黄飞鸿和方世玉都取了钱 140 huangFeiHong.GetMoney(200); 141 fangShiYu.GetMoney(200); 142 beijingBank.Notify(); 143 144 //他们三个都取了钱 145 huangFeiHong.GetMoney(320); 146 fangShiYu.GetMoney(4330); 147 hongXiGuan.GetMoney(332); 148 beijingBank.Notify(); 149 150 Console.Read(); 151 } 152 } 153 }