c#设计模式系列:观察者模式(Observer Pattern)
引言
在现实生活中,处处可见观察者模式,例如,微信中的订阅号,订阅博客和QQ微博中关注好友,这些都属于观察者模式的应用。在这一章将分享我对观察者模式的理解,废话不多说了,直接进入今天的主题。
观察者模式的介绍
2.1 观察者模式的定义
从生活中的例子可以看出,只要对订阅号进行关注的客户端,如果订阅号有什么更新,就会直接推送给订阅了的用户。从中,我们就可以得出观察者模式的定义。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己的行为。
2.2 观察者模式的结构图
可以看出,在观察者模式的结构图有以下角色:
- 抽象主题角色(Subject):抽象主题把所有观察者对象的引用保存在一个列表中,并提供增加和删除观察者对象的操作,抽象主题角色又叫做抽象被观察者角色,一般由抽象类或接口实现。
- 抽象观察者角色(Observer):为所有具体观察者定义一个接口,在得到主题通知时更新自己,一般由抽象类或接口实现。
- 具体主题角色(ConcreteSubject):实现抽象主题接口,具体主题角色又叫做具体被观察者角色。
- 具体观察者角色(ConcreteObserver):实现抽象观察者角色所要求的接口,以便使自身状态与主题的状态相协调。
2.3观察者模式的实现
下面我们已抖音为例,当你刷抖音时候,看到一个很不错的小视频,就关注了这个作者,以后作者每次更新视频的时候,系统都会给关注他的粉丝推送新的消息,下面是我写的第一版实现代码:


/// <summary>
/// 作者
/// </summary>
public class OAuth
{
private List<Fans> list = new List<Fans>();
public string name { get; set; } /// <summary>
/// 新增一个粉丝
/// </summary>
/// <param name="add"></param>
public void Add(Fans add)
{
list.Add(add);
}
/// <summary>
/// 减少一个粉丝
/// </summary>
/// <param name="remove"></param>
public void Remove(Fans remove)
{
list.Remove(remove);
}
public void Nofify()
{
foreach (Fans item in list)
{
item.Update();
}
}
}
/// <summary>
/// 粉丝
/// </summary>
public class Fans
{ private string name;
private OAuth sub;
public Fans(string name, OAuth sub)
{
this.name = name;
this.sub = sub;
}
public void Update()
{
Console.WriteLine("你好:{0},{1}发布了新的作品,点击查看",name,sub.name);
}
} /// <summary>
/// 客户端
/// </summary>
class Program
{
static void Main(string[] args)
{ OAuth oauth = new OAuth();
oauth.name = "小炒肉";
Fans a = new Fans("青椒",oauth);
Fans b = new Fans("胡萝卜",oauth);
oauth.Add(a);
oauth.Add(b); oauth.Nofify(); Console.ReadLine();
}
}
//结果显示
你好:青椒,小炒肉发布了新的作品,点击查看
你好:胡萝卜,小炒肉发布了新的作品,点击查看
看到这种代码我们首先想到的是 违反了面向对象的开发-封闭原则,其次是依赖倒转原则,类与类之间不应该相互依赖,而应该依赖与抽象,好了,我们得重新修改了,10分钟后第二版出来了


public abstract class Observer
{
protected string name;
protected Subject sub;
public Observer(string name, Subject sub)
{
this.name = name;
this.sub = sub;
}
public abstract void Update();
} public class Person : Observer
{
public Person(string name, Subject sub) : base(name, sub) { } public override void Update()
{
Console.WriteLine("你好:{0},{1}发布了新的作品,点击查看", name, sub.name);
}
}
public abstract class Subject
{
public string name { get; set; }
public abstract void Add(Observer ob);
public abstract void Remove(Observer ob);
public abstract void Notify();
}
public class Green : Subject
{
private List<Observer> list = new List<Observer>();
public override void Add(Observer ob)
{
list.Add(ob);
}
public override void Notify()
{
foreach (var item in list)
{
item.Update();
}
}
public override void Remove(Observer ob)
{
list.Remove(ob);
}
}
/// <summary>
/// 客户端
/// </summary>
class Program
{
static void Main(string[] args)
{
Subject ob = new Green();
ob.name = "小炒肉";
Observer a = new Person("青椒", ob);
Observer b = new Person("胡萝卜", ob);
ob.Add(a);
ob.Add(b);
ob.Notify();
Console.ReadLine();
}
}
///结果
你好:青椒,小炒肉发布了新的作品,点击查看
你好:胡萝卜,小炒肉发布了新的作品,点击查看
现在已经依赖接口编程,但是“抽象通知者”还是依赖 抽象观察者,也就是说,万一没有了抽象观察者这样的接口,我这通知的功能就完成不了,下面我们引入委托解耦实现通知者和观察者


public class Person
{
protected string name;
protected Subject sub;
public Person(string name, Subject sub)
{
this.name = name;
this.sub = sub;
}
public void UpdateTP()
{
Console.WriteLine("你好:{0},{1}发布了新的作品,点击查看", name, sub.name);
}
}
public delegate void EventHandler();
public interface Subject
{
string name { get; set; }
void Notify();
}
public class Green : Subject
{ public event EventHandler Update;
public string name { get; set; } public void Notify()
{
Update();
}
}
/// <summary>
/// 客户端
/// </summary>
class Program
{
static void Main(string[] args)
{
Green hand = new Green();
hand.name = "小王";
Person per = new Person("青椒",hand);
Person Ge = new Person("小炒肉", hand);
hand.Update += new EventHandler(per.UpdateTP);
hand.Update += new EventHandler(Ge.UpdateTP); hand.Notify(); Console.ReadLine();
}
}
总结
在C#的event中,委托充当了抽象的Observer接口,而提供事件的对象充当了目标对象。委托是比抽象Observer接口更为松耦合的设计。
好了在次复习下,观察者模式的定义,观察者模式定义了一种一对多的关系,让多个观察者对象可以同时监听某一个主题对象,这个主题对象在发送状态改变时,会通知所有观察者对象,时它们能够自动更新自己
c#设计模式系列:观察者模式(Observer Pattern)的更多相关文章
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 二十四种设计模式:观察者模式(Observer Pattern)
观察者模式(Observer Pattern) 介绍定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例有一个Message实体类,某些对象 ...
- [设计模式] 19 观察者模式 Observer Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.当一个 ...
- c#设计模式之观察者模式(Observer Pattern)
场景出发 一个月高风黑的晚上,突然传来了尖锐的猫叫,宁静被彻底打破,狗开始吠了,大人醒了,婴儿哭了,小偷跑了 这个过程,如果用面向对象语言来描述,简单莫过于下: public class Cat { ...
- 设计模式之观察者模式(Observer pattern)
最近参加了一次面试,其中笔试题有一道编程题,在更换掉试题的描述场景后,大意如下: 上课铃声响起,学生A/B/C/D进入教室:下课铃声响起,学生A/B/C/D离开教室. 要求使用设计模式的思想完成铃与学 ...
- 设计模式九: 观察者模式(Observer Pattern)
简介 观察者属于行为型模式的一种, 又叫发布-订阅模式. 如果一个对象的状态发生改变,依赖他的对象都将发生变化, 那么这种情况就适合使用观察者模式. 它包含两个术语,主题(Subject),观察者(O ...
- 【设计模式】观察者模式 Observer Pattern
定义:观察者模式定义了对象之间的一对多依赖.当“主题”(Object)状态改变事,所有依赖它的“观察者”(Observer)都会受到通知并自动更新.主题支持观察者订阅和退订. 观察者模式提供了一种对象 ...
- 【UE4 设计模式】观察者模式 Observer Pattern
概述 描述 定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新.观察者模式又叫做 发布-订阅(Publish/Subscribe)模式 模型-视图(M ...
- 设计模式-观察者模式(Observer Pattern)
观察者模式(Observer Pattern):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己. 观察者 ...
- 设计模式 - 观察者模式(Observer Pattern) 详细说明
观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...
随机推荐
- 解决“在上下文中找不到 owin.Environment 项”
网站发布到虚拟空间后,提示以下错误:在上下文中找不到 owin.Environment 项",百度了好长时间都没有解决.最后在web.config中添加以下配置. <system.we ...
- flutter photo_view的改造
app中对图片的浏览.缩放是一个常用的功能,目前有一款插件photo_view,基本上可以满足这些功能,但是有些地方需要修改完善 1.双击放大的时候,有三个状态,会有一个放大的中间状态,需要点击三次才 ...
- Java枚举类的serialVersionUID
起因 最近在公司里敲代码的时候偶然间发现以前留下的枚举类实现了Serializable接口,然后写了个serialVersionUID...我以前一直没在枚举类里使用过..觉得有点神奇....于是百度 ...
- Spring、Springboot常用注解:@Qualifier(不定时更新)
1.@Qualifier 出现场景: 老项目中有多个实现类实现同一个接口时,或者一个项目中有多个数据源时,spring容器不知道该注入哪个实现类或者使用哪个数据源,该注解就派上用场. 1)多实现类实现 ...
- javascript 模拟选择下拉框的某一个option元素的效果
需要在单元测试模拟它,百度谷歌了好久都没有.后来认真想想,还是找到办法了.因为我们手动交互某一行为,首先是让它的某些属性发生变化,其次是让它触发某事件.想明白这一点就简单了.让属性发生变化,当然是改动 ...
- PHP中使用CURL模拟文件上传实例
调用实例: 该方法将本地的E盘文件test.doc上传到接口服务器上的 uploadFile方法中,uploadFile会对上传的文件做进一步处理. 若你想自己对上传的文件做操作,将接口uploadF ...
- 【bzoj2242】[SDOI2011]计算器
2242: [SDOI2011]计算器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3207 Solved: 1258[Submit][Statu ...
- 解剖Nginx·自动脚本篇(7)类型相关脚本系列
1 auto/types/sizeof 该脚本的功能,是通过测试程序获知给定的ngx_type的大小. 1.1 显示提示信息 echo $ngx_n "checking for $ngx_t ...
- 解剖Nginx·模块开发篇(1)跑起你的 Hello World 模块!
1 学习 Nginx 模块开发需要有哪些准备? 需要的预备知识不多,有如下几点: 有过一些 C 语言的编程经历: 知道 Nginx 是干嘛的,并有过编写或改写 Nginx 的配置文件的经历. OK,就 ...
- Codeforces 703E DP + 因数分解 +离散化
题意:给你n个数,和一个数m, 问最小需要多少个数,可以让这些数乘起来是m的倍数.如果有多组,取和最小的那一组. 思路:因为m的范围到1e12,并且和取模相关,所以容易想到处理出m的约数,然后离散化一 ...