设计模式(行为模式)——观察者模式

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的任务。代码示例见表现层设计模式那一章。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏闵开慧

Mapreduce任务实现邮件监控

Mapreduce任务实现邮件监控     这里主要使用Java自带邮件类实现Mapreduce任务的监控,如果Mapreduce任务报错则发送报错邮件。Map...

3218
来自专栏web开发

java导出Excel表格

最近自己着手写了一个前后端分离的后台管理系统(主要是写着玩,java还是熟悉一点,所以前后端均是自己写),后端使用的Java SpringMVC。后来想着在用户...

29510
来自专栏余林丰

观察者模式

订阅者模式通常也成为发布-订阅模式,发布者也称为通知者,订阅者也称为观察者。通知者发出通知,各发布者则收到通知后做出相应的动作。由于存在不同的订阅者和通知者,所...

1897
来自专栏跟着阿笨一起玩NET

Winfrom 如何安全简单的跨线程更新控件

来源:http://www.cnblogs.com/rainbowzc/archive/2010/09/29/1838788.html

511
来自专栏后端之路

为什么说dubbo的声明式缓存不好用!!!

那么通常提供缓存的目的是什么呢? 关于两级缓存的说明 通常为了更快的速度(以及一定的稳定性) 那么dubbo中的实现是通过filter机制基本上来缓存了我们需要...

1.2K5
来自专栏DOTNET

asp.net web api 下载之断点续传

一、基本思想 利用 HTTP 请求的Range标头值,来向服务端传递请求数据的开始位置和结束位置。服务端获得这两个参数后,将指定范围内的数据传递给客户端。当客户...

44812
来自专栏菩提树下的杨过

Replace方法与正则表达式的性能比较

今天做项目时遇到一个小需求:要将字符串中的回车符号替换成其它符号(比如"<br/>")。 考虑到不同的情况下,有些系统中是用\r\n作回车符,有些仅用\n就代表...

1939
来自专栏Golang语言社区

如果裸写一个goroutine pool

引言 在上文中,我说到golang的原生http server处理client的connection的时候,每个connection起一个goroutine,这...

4086
来自专栏hbbliyong

Extjs4.2+webAPI+EF实现分页以及webapi的数据传值

由于不明白分页的总数是怎么计算,不知道他的分页方式所以花费了好多功夫,现在弄出来了与大家分享下 1.首先是EF的简历,想必大家都清楚:添加-〉新建项-〉数据-〉...

3094
来自专栏漫漫前端路

巧用 TypeScript(二)

Decorator 早已不是什么新鲜事物。在 TypeScript 1.5 + 的版本中,我们可以利用内置类型 ClassDecorator、PropertyD...

722

扫码关注云+社区