观察者模式
一、完成者信息:
姓名:周义
学号:07770207
二、模式信息
模式名称:观察者模式
模式概述:
在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新
生活场景:假设有一个非常漂亮的女孩,就叫他美女吧!漂亮的女孩总是有很多的追求者,而且追求者的队伍在不断的变动,随时有人进入这个队伍,也有人退出。男孩们追求女孩时总是表现出200%的关心,当美女私自游玩时总是不断收到追求者询问她的位置变动和跟谁在一块的短信,美女肯定不胜其烦,如果她是一个善良的女孩,她会回复每个男孩的消息。而男孩们由于要不断的关心美女的动态,不断的发短信,美女不断的回短信,这样下去可想而知.
终极目标:实现自动发送更新的位置信息给每一个追求者。
- 1. 不假思索的思路:
不假思索的思路就不用说了,就如上面场景描述的一样,美女位置变动,boys发短信询问美女位置,美女一一回答,他们在作出相应的反应。美女和男孩们之间形成了一种双向的依赖关系,耦合性太强。
类图:
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Observer1
{
/// <summary>
/// 男孩类
/// </summary>
public class Boy
{
private string name;
public string Name//字段封装
{
get { return name; }
set { name = value; }
}
public Boy(string name)
{
this.name = name;
}
/// <summary>
/// 询问位置
/// </summary>
public void Ask()
{
Console.WriteLine(name + "询问美女位置?");
}
}
/// <summary>
/// 美女类
/// </summary>
public class Girl
{
/// <summary>
/// 回复信息
/// </summary>
/// <param name="address"></param>
public void SendMessage(string address)
{
Boy boy = new Boy("张无忌");
boy.Ask();
Console.WriteLine(boy.Name + "我在" + address + "别来烦我!");
//Boy boy1 = new Boy("宋青书");
//boy1.Ask();
//Console.WriteLine(boy1.Name + "我在" + address + "别来烦我!");
}
}
class Program
{
static void Main(string[] args)
{
Girl girl =new Girl();
girl.SendMessage("广水");
Console.ReadKey();
}
}
}
可以看得出来:要对不同的人发每次都不得不修改Girl类
- 2. 归纳阶段
对于上面的场景问题,我提出一个解决方案,假设女孩手机保存着一个订阅位置变化短信通知的电话列表,当美女位置发生变化就会向这个订阅列表里的所有手机发送短信。看到这个解决方案,男孩们和美女都应该松一口气了
对于女孩,我抽象出一个接口,用来添加追求者
对于观察者,抽象出一个更新接口,通知观察者美女的位置
在上面的解决方案中就透露出观察者模式的思想:观察者模式定义了对象之间一对多的依赖,当这个对象的状态发生改变的时候,多个对象会接受到通知,有机会做出反馈。在运行的时刻可以动态的添加和删除观察者。
带着这个定义我们来看看尝试实现上面的观察者模式 。首先在观察者模式中我们必须定义一个所有“观察者”都必须实现的接口,这样被观察者向观察者发送消息的时候就可以使用统一的方式,这也符合面相对象原则中的面向接口编程:
类图:
代码:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Observer
7 {
8 public interface IBoy
9 {
10
11 void Show(string address);//向男孩们显示美女位置情况,也就是向观察者发送消息,观察者还可以对此做出反馈
12 }
13
14
15 public interface BGirl
16 {
17 void AddBoy(IBoy boys);//针对那些观察者——这男孩们
18 //void RemoveBoy(IBoy boys);
19 }
20
21
22 public class Boy : IBoy
23 {
24 //IBoy 成员
25
26 private string name;
27
28
29 public Boy(string name, BGirl girl)
30 {
31 this.name = name;
32 girl.AddBoy(this);
33 //girl.RemoveBoy(this);
34 }
35
36
37
38 public void Show(string address)
39 {
40 Console.WriteLine(name + "我在" + address + "别来烦我");
41 }
42
43
44 }
45
46
47 public class Girl : BGirl
48 {
49 //保存观察者
50 private List<IBoy> boys;
51
52 public Girl()
53 {
54 this.boys = new List<IBoy>();
55 }
56
57 public Boy Boy
58 {
59 get
60 {
61 throw new System.NotImplementedException();
62 }
63 set
64 {
65 }
66 }
67
68 //添加追求者
69 public void AddBoy(IBoy boy)
70 {
71 this.boys.Add(boy);
72 }
73
74 //移除追求者
75 public void RemoveBoy(IBoy boy)
76 {
77 this.boys.Remove(boy);
78 }
79
80 //通知
81 public void ChangeAddress(string address)
82 {
83 Console.WriteLine("位置变动");
84 foreach (IBoy boy in this.boys)
85 {
86 boy.Show(address);
87 }
88 }
89
90 }
91
92
93
94 class Program
95 {
96
97 static void Main(string[] args)
98 {
99 Girl girl = new Girl();
100 Boy boy1 = new Boy("张无忌", girl);
101 Boy boy2 = new Boy("宋青书", girl);
102 Boy boy3 = new Boy("陈友谅", girl);
103 Boy boy4 = new Boy("周义", girl);//新添加的观察者
104 girl.RemoveBoy(boy1);
105 girl.ChangeAddress("广水");
106 Console.Read();
107
108 }
109 }
110 }
3.验证阶段:
当前目标:增加一个人的特征维度,证明该模式的适用性;
在上面的例子中我们可以看到被观察者仅仅依赖于一个实现了观察者接口的列表,我们可以随时的向这个列表添加观察者,当我们向观察者族中添加或者一个观察者,被观察者和无关的观察者无须作任何改变,只需在客服端进行修改。
客服端应用程序修改为:
static void Main(string[] args)
{
Girl girl=new Girl();
Boy boy1 = new Boy("张无忌", girl);
Boy boy2 = new Boy("宋青书", girl);
Boy boy3 = new Boy("陈友谅", girl);
Boy boy4 = new Boy("周义", girl);//新添加的观察者
girl.RemoveBoy(boy1);//从观察者列表中移除boy1
girl.ChageAddress("广水");
Console.Read();
}
可以看出通过这个解决方案,取消了直接依赖,变为间接依赖,这样大大提供了系统的可维护性和可扩展性。