观察者模式(Observer Pattern):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主体对象,这个主题对象在状态发生变化时,会通知所有观察者。当一个对象改变需要同时改变其他对象,而且他不知道具体有多少对象需要改变的时候,应该考虑使用观察者模式。

观察者模式有四个角色:抽象主题、具体主题、抽象观察者、具体观察者。

ISubject接口(抽象目标):把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。含方法Notify,Register,UnRegister(名字可以自己任意取名)

Subject类(实体目标):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。实现ISubject接口,一般只有一个

IObservable接口(抽象观察者):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

Observer类(实体观察者):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。实现IObservable接口,一般有多个

观察者模式中的“注册--通知--注销”图示:
1. 观察者(Observer)将自己(Regiester)注册到被观察对象(Subject)中,被观察对象将观察者放在一个容器(Container)。Container一般为Ilist,Arraylist等数据结构,存放多个IObservable接口变量。
2.当被观察对象(Subject)发生变化时,容器(Container)中的所有观察者(Observer)都得到通知(Notify 方法),此时观察者会自动执行某些方法。
3.当观察者不想继续观察被观察者时,可以注销(UnRegiester方法)

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

实现代码

抽象观察者(IObservable):

     /// <summary>
/// 只是为了把多个对象产生关系,方便保存和调用
/// 方法本身其实没用
/// </summary>
public interface IObserver
{
void Action();
}

实体观察者(Observer):

     public class Baby : IObserver
{
public void Action()
{
this.Cry();
} public void Cry()
{
Console.WriteLine("{0} Cry", this.GetType().Name);
}
}
     public class Brother : IObserver
{
public void Action()
{
this.Turn();
}
public void Turn()
{
Console.WriteLine("{0} Turn", this.GetType().Name);
}
}
     public class Chicken : IObserver
{
public void Action()
{
this.Woo();
}
public void Woo()
{
Console.WriteLine("{0} Woo", this.GetType().Name);
}
}
     public class Dog : IObserver
{
public void Action()
{
this.Wang();
}
public void Wang()
{
Console.WriteLine("{0} Wang", this.GetType().Name);
}
}
     public class Father : IObserver
{
public void Action()
{
this.Roar();
}
public void Roar()
{
Console.WriteLine("{0} Roar", this.GetType().Name);
}
}
     public class Mother : IObserver
{
public void Action()
{
this.Whisper();
}
public void Whisper()
{
Console.WriteLine("{0} Whisper", this.GetType().Name);
}
}
     public class Mouse : IObserver
{
public void Action()
{
this.Run();
}
public void Run()
{
Console.WriteLine("{0} Run", this.GetType().Name);
}
}
     public class Neighbor : IObserver
{
public void Action()
{
this.Awake();
}
public void Awake()
{
Console.WriteLine("{0} Awake", this.GetType().Name);
}
}
     public class Stealer : IObserver
{
public void Action()
{
this.Hide();
}
public void Hide()
{
Console.WriteLine("{0} Hide", this.GetType().Name);
}
}

实体目标(Subject):

     /// <summary>
/// 一只神奇的猫
///
/// 猫叫一声之后触发
/// baby cry
/// brother turn
/// dog wang
/// father roar
/// mother whisper
/// mouse run
/// neighbor awake
/// stealer hide
///
/// </summary>
public class Cat
{
public void Miao()
{
Console.WriteLine("{0} Miao.....", this.GetType().Name); new Mouse().Run();//依赖
new Chicken().Woo();
new Baby().Cry();
new Brother().Turn();
new Dog().Wang();
new Father().Roar();
new Mother().Whisper();
//new Mouse().Run();
new Neighbor().Awake();
//new Stealer().Hide();
}
//依赖太多,任何一个对象改动,都会导致Cat变化
//违背了单一职责,不仅自己miao 还要触发各种动作,不稳定
//加一个/减一个/调整顺序 Cat都得改 //Cat职责:1 Miao 2 触发一系列动作 这是需求
//实现上,其实多了一个,3 指定动作 //Cat不稳定--这一堆对象--甩锅--自己不写让别人传递
private List<IObserver> _ObserverList = new List<IObserver>();
public void AddObserver(IObserver observer)
{
this._ObserverList.Add(observer);
}
public void MiaoObserver()
{
Console.WriteLine("{0} MiaoObserver.....", this.GetType().Name);
if (this._ObserverList != null && this._ObserverList.Count > )
{
foreach (var item in this._ObserverList)
{
item.Action();
}
}
} public event Action MiaoHandler;
public void MiaoEvent()
{
Console.WriteLine("{0} MiaoEvent.....", this.GetType().Name);
if (this.MiaoHandler != null)
{
foreach (Action item in this.MiaoHandler.GetInvocationList())
{
item.Invoke();
}
}
} }

前端调用:

                 {
Console.WriteLine("***************Common******************");
Cat cat = new Cat();
cat.Miao();
}
{
Console.WriteLine("***************Observer******************");
Cat cat = new Cat();
cat.AddObserver(new Mouse());
cat.AddObserver(new Chicken());
cat.AddObserver(new Baby());
cat.AddObserver(new Brother());
cat.AddObserver(new Dog());
cat.AddObserver(new Father());
cat.AddObserver(new Mother());
cat.AddObserver(new Mouse());
cat.AddObserver(new Neighbor());
cat.AddObserver(new Stealer());
cat.MiaoObserver();
} {
Console.WriteLine("***************Observer******************");
Cat cat = new Cat();
cat.MiaoHandler += new Baby().Cry;
cat.MiaoHandler += new Brother().Turn;
cat.MiaoHandler += new Dog().Wang;
cat.MiaoHandler += new Stealer().Hide;
cat.MiaoHandler += new Neighbor().Awake;
cat.MiaoHandler += new Father().Roar;
cat.MiaoEvent();
}

交互的对象之间应尽量设计成松耦合的

松耦合设计可以让我们设计出这样的系统: 因为对象之间的相互依存减小了, 所以系统可以轻松处理变化

松耦合系统通常是基于消息的系统,此时客户端和远程服务并不知道对方是如何实现的。客户端和服务之间的通讯由消息的架构支配。只要消息符合协商的架构,则客户端或服务的实现就可以根据需要进行更改,而不必担心会破坏对方

当两个对象是松耦合的时候, 他们可以进行交互, 但是却几乎不了解对方.
观察者模式下的被观察者(Subject)和观察者(Observers)就是松耦合设计的对象. 这是因为:

    • 被观察者(Subject)只知道观察者实现了某个接口

    • 可以随时添加观察者

    • 添加新类型观察者的时候不需要修改被观察者

    • 可以复用观察者或者被观察者

    • 如果被观察者或观察者发生变化了, 那么这些变化不会影响到对方

使用委托的时候, 通常会有两个角色出现: 广播者(被观察者)和订阅者(观察者) [观察者模式]

广播者包含一个委托field, 广播者决定何时广播, 它通过调用委托进行广播.

订阅者就是方法的目标接收者.订阅者可以决定何时开始和结束监听, 是通过在广播者的委托上使用+=和-=操作符来实现的.

订阅者之间互相不了解, 不干扰.

event就是为上述模型所存在的, 它只把上述模型所必须的功能从委托里暴露出来. 它的主要目的就是防止订阅者之间相互干扰.

最简单声明event的方法就是在委托成员前面加上event关键字

本文参考文档:

https://www.runoob.com/design-pattern/observer-pattern.html

https://www.cnblogs.com/abcdwxc/archive/2007/09/19/898856.html

https://www.cnblogs.com/zhiyong-ITNote/p/10970067.html

https://mp.weixin.qq.com/s/XkfiFKPTbOy6kGGzfQOFpA

https://www.jb51.net/article/31665.htm

https://blog.csdn.net/u011966339/article/details/69388534

23种设计模式之观察者模式(Observer Pattern)的更多相关文章

  1. 二十四种设计模式:观察者模式(Observer Pattern)

    观察者模式(Observer Pattern) 介绍定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例有一个Message实体类,某些对象 ...

  2. 实践GoF的23种设计模式:观察者模式

    摘要:当你需要监听某个状态的变更,且在状态变更时通知到监听者,用观察者模式吧. 本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:观察者模式>,作者: 元闰子 . 简介 现在有 ...

  3. 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

    原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...

  4. 23种设计模式之观察者模式(Observer)

    观察者模式又称为发布—订阅模式.模型—视图模式.源-监听器模式或从属者(dependents)模式,是一种对象的行为型模式.它定义了对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时,其相 ...

  5. 【Unity与23种设计模式】观察者模式(Observer)

    GoF中定义: "在对象之间定义一个一对多的连接方法,当一个对象变换状态时,其他关联的对象都会自动收到通知." 现实中,社交网络就是个例子. 以前的报社,每次出新刊的时候, 报刊便 ...

  6. [设计模式] 19 观察者模式 Observer Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.当一个 ...

  7. c#设计模式之观察者模式(Observer Pattern)

    场景出发 一个月高风黑的晚上,突然传来了尖锐的猫叫,宁静被彻底打破,狗开始吠了,大人醒了,婴儿哭了,小偷跑了 这个过程,如果用面向对象语言来描述,简单莫过于下: public class Cat { ...

  8. 设计模式之观察者模式(Observer pattern)

    最近参加了一次面试,其中笔试题有一道编程题,在更换掉试题的描述场景后,大意如下: 上课铃声响起,学生A/B/C/D进入教室:下课铃声响起,学生A/B/C/D离开教室. 要求使用设计模式的思想完成铃与学 ...

  9. 设计模式九: 观察者模式(Observer Pattern)

    简介 观察者属于行为型模式的一种, 又叫发布-订阅模式. 如果一个对象的状态发生改变,依赖他的对象都将发生变化, 那么这种情况就适合使用观察者模式. 它包含两个术语,主题(Subject),观察者(O ...

随机推荐

  1. python学习——列表生成式,生成器和迭代器

    列表生成式 列表生成式,是python内置的非常简单却强大的可以用来创建list的生成式.它可以极大的简化语句. """列表生成式""" # ...

  2. unity编辑器扩展_04(使用Selection获取选择的游戏物体)

    代码: [MenuItem("Tools/GetChance", false, 1)]    static void GetChance()    {        if (Sel ...

  3. JAVA解除tomcat 对浏览器特别字符 | () {} [] 的限制

    1.打开tomcat本机地址打开conf文件夹(一定要关闭Tomcat启动在修改) 2.记事本打开或者编辑软件打开(我这里推荐的编辑软件是以下如图) 打开进去加入这两行代码 3打开server.xml ...

  4. eclipse中导入外部包却无法查看对应源码或Javadoc的入坑指南

    eclipse中导入外部包却无法查看对应源码或Javadoc的 入坑指南 出现这个错误的原因是,你虽然导入了.jar包,但没有配置对应的Javadoc或源码路径,所以在编辑器中无法查看源 码和对应AP ...

  5. 在IIS下部署PHP

    没有.net ramework 4.0 的要先安装 dotNetFx40_Full_x86_x64.exe PHP压缩包 推荐用5.6.29版 IIS下PHP压缩包下载地址:"http:// ...

  6. 决胜Flutter 第一章 熟悉战场

    欢迎参加“决胜Flutter” 实训课程,这里是你此次实训之旅的起点. 本章将带您快速了解移动开发的现状,然后向您介绍Flutter的发展历史以及优势特点,最后一起动手,搭建高效的开发环境. 由于Fl ...

  7. HBase工作中的一些优化方法

    1.表的设计 Pre-creating Regions(预分区) 默认情况下,在创建Hbase表的时候会自动创建一个region分区,当导入数据的时候,所有的Hbase客户端都向这一个region写数 ...

  8. KafkaProducer源码分析

    Kafka常用术语 Broker:Kafka的服务端即Kafka实例,Kafka集群由一个或多个Broker组成,主要负责接收和处理客户端的请求 Topic:主题,Kafka承载消息的逻辑容器,每条发 ...

  9. SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询

    背景&痛点 通过ES进行查询,如果需要新增查询条件,则每次都需要进行硬编码,然后实现对应的查询功能.这样不仅开发工作量大,而且如果有多个不同的索引对象需要进行同样的查询,则需要开发多次,代码复 ...

  10. android中shape 的使用

    android 开发中 对于 shape 和 selector的使用,一直都不是很熟练, 记录一下.便于以后参考. 举个项目中例子图 对于上面的2个radiobutton ,背景我们可以让美工做一个. ...