设计模式(行为模式)——观察者模式
1 定义
定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2 适用性
1)当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2)当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时。
3)当一个对象必须通知其他对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的。
3 结构
说明:
1)Subject(目标):目标知道它的观察者。可以有任意多个观察者观察同一个目标。提供注册和删除观察者对象的接口。
2)Observer(观察者):为那些在目标发生改变时需要获得通知的对象定义一个更新接口。
3)ConcreteSubject(具体目标):将有关状态存入各ConcreteObserver对象。当它的状态发生改变时,向它的各个观察者发出通知。
4)ConcreteObserver(具体观察者):维护一个指向ConcreteSubject对象的引用。存储有关状态,这些状态应与目标的状态保持一致。实现Observer的更新接口以使自身状态与目标的状态保持一致。
举例:
1消息广播
一个消息发布者,两个消息订阅者。发布者广播新的消息时,所有的订阅者都自动接收新的消息。
目标(发布者)
public interface ISubject
{
void SendMessage(string message);
}
目标的实现
public class Subject : ISubject
{
public Action<string> PublishMessage;
public void SendMessage(string message)
{
PublishMessage(message);
}
}
观察者(订阅者)
public interface IObserver
{
void GetNewMessage(string message);
}
public class Person1 : IObserver
{
public void GetNewMessage(string message)
{
Console.WriteLine("第一个人接收到新消息:" + message);
}
}
public class Person2 : IObserver
{
public void GetNewMessage(string message)
{
Console.WriteLine("第二个人接收到新消息:" + message);
}
}
连接目标与观察者
static void Main(string[] args)
{
Person1 pf = new Person1();
Person2 p2 = new Person2();
Subject s = new Subject();
s.PublishMessage += pf.GetNewMessage;
s.PublishMessage += p2.GetNewMessage;
while(true)
{
Console.WriteLine("广播消息:");
s.SendMessage(Console.ReadLine());
}
}
运行结果:
2 模拟温度调控器
设置最高温与最低温,当输入温度大于最高温时,开始冷却器,关闭加热器;当输入温度小于最低温时,相反。
目标(发布者)
public interface ISubject
{
float CurrentTemperature { get; set; }
}
目标实现
public class Subject:ISubject
{
private float _CT;
public Action<float> PublishMessage;
public float CurrentTemperature
{
get
{
return _CT;
}
set
{
if (this._CT != value)
{
PublishMessage(value);
}
}
}
}
观察者(订阅者)
public interface IObserver
{
float Temperature { get; set; }
void TemperatureChanged(float newTemperature);
}
加热器:
public class Heater : IObserver
{
public float Temperature { set; get; }
public Heater(float temperature)
{
Temperature = temperature;
Console.WriteLine("温度最大值:" + temperature);
}
public void TemperatureChanged(float newTemperature)
{
if (newTemperature > Temperature)
{
Console.WriteLine("加热器关闭");
}
else if (newTemperature == Temperature)
{
Console.WriteLine("加热器关闭");
}
else
{
Console.WriteLine("加热器开启");
}
}
}
制冷器:
public class Cooler : IObserver
{
public Cooler(float temperature)
{
Temperature = temperature;
Console.WriteLine("温度最小值:" + temperature);
}
public float Temperature{set;get;}
public void TemperatureChanged(float newTemperature)
{
if (newTemperature > Temperature)
{
Console.WriteLine("制冷器开启");
}
else if (newTemperature == Temperature)
{
Console.WriteLine("制冷器关闭");
}
else
{
Console.WriteLine("制冷器关闭");
}
}
}
连接目标与观察者
static void Main(string[] args)
{
Heater h = new Heater(60);
Cooler c = new Cooler(50);
Pattern.Observer.Subject sub = new Pattern.Observer.Subject();
sub.PublishMessage += h.TemperatureChanged;
sub.PublishMessage += c.TemperatureChanged;
while (true)
{
Console.WriteLine("输入温度:");
string temp = Console.ReadLine();
sub.CurrentTemperature = float.Parse(temp);
}
}
运行结果:
3 观察者模式在Winform中的应用
在PM模式中,视图没有向控制器暴露出任何接口,那么控制器如何更新视图UI呢?一种比较简单的方式就是利用观察者模式。控制器相当于目标,视图层相当于观察者,当控制器接收到视图层数据后,更新模型,然后向所有观察者广播这一消息,视图层接收到消息后,完成更新UI的任务。代码示例见表现层设计模式那一章。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 微信小程序封装api接口
- 手把手教你,嘴对嘴传达------Nginx常规的优化(隐藏版本号,缓存时间,日志切割,网页压缩,防盗链优化)
- Vue Router 实现多种页面跳转
- Vue实现输入框自动聚焦
- 手把手教你,嘴对嘴传达------Apache --ab测试
- Css实现内容溢出添加横向滚动条
- 手把手教你,嘴对嘴传达------深入介绍Nginx的rewrite模块(理论加实验)
- jQuery实现点击图片弹出视频并自动播放
- 机器学习之决策树一-ID3原理与代码实现
- jQuery点击返回顶部
- 手把手教你,嘴对嘴传达------Nginx实现动静分离的两种方式
- Vue实现push数组并删除方法
- 机器学习之决策树二-C4.5原理与代码实现
- Vue Router懒加载
- 手把手教你,嘴对嘴传达------Tomcat部署和优化以及虚拟主机配置