面向对象编程思想-观察者模式

一、引言

相信猿友都大大小小经历过一些面试,其中有道经典题目,场景是猫咪叫了一声,老鼠跑了,主人被惊醒(设计有扩展性的可加分)。对于初学者来说,可能一脸懵逼,这啥跟啥啊是,其实博主当年也这感觉,O(∩_∩)O哈哈~好了,废话不多说,今天我们要学习的内容就是要解决这种业务场景——观察者模式,又叫发布-订阅(Publish/Subscrible)模式

二、观察者模式

定义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象状态发生变化时,会通知所有观察者对象,使它们能够自行更新自己

下面是观察者模式结构图:

                          该图示出自“大话设计模式”


下面通过大家都熟悉的生活场景来帮助我们一步步了解观察者模式

场景:上自习课的时候,困了想睡觉,通常是会跟同桌说:“老师来了叫我下,我睡会”。(大多数人都是这样吧,嘿嘿)

下面是代码demo:

    //主题类class ConcreteSubject{private IList<ConcreteObserver> lstConcreteObserver = new List<ConcreteObserver>();private string action;//添加观察者public void Add(ConcreteObserver concreteObserver){lstConcreteObserver.Add(concreteObserver);}//移除观察者public void Remove(ConcreteObserver concreteObserver){lstConcreteObserver.Remove(concreteObserver);}//通知观察者类public void Notify(){foreach (ConcreteObserver observer in lstConcreteObserver){observer.Update();}}//定义主题发现的某一状态public string ConcreteAction{get { return action; }set { action = value; }}}//观察者类class ConcreteObserver{protected ConcreteSubject subject;protected string name;public ConcreteObserver(ConcreteSubject subject, string name){this.subject = subject;this.name = name;}//观察者更新行为public void Update(){Console.WriteLine($"{subject.ConcreteAction},{name},别睡觉了,快醒醒!");}}static void Main(string[] args){ConcreteSubject subject = new ConcreteSubject();ConcreteObserver observer = new ConcreteObserver(subject, "michael");subject.Add(observer);subject.ConcreteAction = "老师来了";subject.Notify();Console.Read();}
View Code

分析:乍一看是写的不错,实现了老师来时同桌通知michael,但是仔细想一下,假如现在情况变了,同桌另一边的同学在打游戏,也让老师来时通知一下,怎么办?这时我们就需要去修改ConcreteSubject类中对观察者ConcreteObserver的引用,还有另外一种情况,假如某天同桌请假了,通常会让前后排的同学通知观察者,即修改观察者类ConcreteObserver中对ConcreteSubject的引用。这种相互耦合的设计显然是不太好,当场景变了的时候,不得不去修改原有代码,违背了开放-封闭原则。

下面看一下大话设计模式中的例子是如何介绍观察者模式的:

     //抽象观察者类abstract class Observer{public abstract void Update();}//抽象主题类abstract class Subject{private IList<Observer> lstConcreteObserver = new List<Observer>();public void Add(Observer concreteObserver){lstConcreteObserver.Add(concreteObserver);}public void Remove(Observer concreteObserver){lstConcreteObserver.Remove(concreteObserver);}public void Notify(){foreach (Observer observer in lstConcreteObserver){observer.Update();}}}//具体观察者类class ConcreteObserver:Observer{protected ConcreteSubject subject;protected string name;private string observerState;public ConcreteObserver(ConcreteSubject subject, string name){this.subject = subject;this.name = name;}public override void Update(){this.observerState = subject.ConcreteAction;Console.WriteLine($"the observer's of {name} state is {observerState}");}}//具体主题对象class ConcreteSubject:Subject{      private string action;      public string ConcreteAction{get { return action; }set { action = value; }}}static void Main(string[] args){ConcreteSubject subject = new ConcreteSubject();subject.Add(new ConcreteObserver(subject, "michael"));subject.Add(new ConcreteObserver(subject, "jarle"));subject.Add(new ConcreteObserver(subject, "cumming"));subject.ConcreteAction = "Ready";subject.Notify();Console.Read();}
View Code

 分析:这次是不是可扩展性更高了?嗯,是的。观察者与主题对象都依赖于抽象,而不依赖与具体,使得各自变化都不会影响到另一边

其实现在已经很好了,但是这样具体的观察者都要依赖于观察者的抽象,那能不能再进行优化一次呢?答案是完全可以的。

下面我们用委托事件来解决开头那个考烂了的面试题,解释如何优化的

委托:是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用

    class Mao{private string name;public delegate void MaoDelegateHandler();public event MaoDelegateHandler MaoEventHandler;public Mao(string name){this.name = name;}public void Miao(){Console.WriteLine($"{this.name}叫了一声");Notify();}public void Notify(){if (MaoEventHandler != null)MaoEventHandler();}public string Name{get { return name; }set { name = value; }}}class Laoshu{public void Run(){Console.WriteLine("老鼠逃跑了");}}class People{public void Wake(){Console.WriteLine("主人被惊醒了");}}class Program{static void Main(string[] args){Mao mao = new Mao("大脸猫");Laoshu laoshu = new Laoshu();People people = new People();//注册事件 这两种方式都可以mao.MaoEventHandler += new Mao.MaoDelegateHandler(laoshu.Run);mao.MaoEventHandler += people.Wake;//猫叫了一声 会自动调用注册过的方法
            mao.Miao();Console.Read();}}
View Code

分析:用委托事件来实现,发布者和订阅者之间没有耦合,是不是有优化了一步呢?O(∩_∩)O~

优点:

1.观察者模式解除了发布者和订阅者的耦合,两者都依赖于抽象,而不是具体的,使得两者可以各自独立的变化

缺点:

1.观察者对象如果很多的话,被观察者通知会耗时增多

2.在被观察者之间如果有相互依赖的话,会相互调用,导致系统崩溃(小白注意)

适用场景:

1.当一个对象改变需要改变其它对象时,而且不知道有多少个对象需要改变

2.当一个抽象模型有两个方面,一个方面依赖于另一个方面,将两者封装在独立的对象中以使它们可以各自独立的变化和复用

 

介绍到这里其实观察这模式已经结束了,但是我觉得很多小白搞不懂winform开发程序中的grid单击、双击等事件,方法后面的参数sender和e分别是什么。。。下面再简要分析一下

    class Mao{private string name;//声明委托public delegate void MaoDelegateHandler(object sender, MaoEventArgs e);//声明事件public event MaoDelegateHandler MaoEventHandler;public class MaoEventArgs : EventArgs{private string name;public MaoEventArgs(string name){this.name = name;}}public Mao(string name){this.name = name;}//发布者 某一行为后 发出通知public void Miao(){Console.WriteLine($"{this.name}叫了一声");//建立MaoEventArgs对象MaoEventArgs e = new MaoEventArgs(this.Name);//调用通知方法
            Notify(e);}public void Notify(MaoEventArgs e){//如果有订阅者注册if (MaoEventHandler != null)//执行所有注册的方法MaoEventHandler(this,e);}public string Name{get { return name; }set { name = value; }}}class Laoshu{//是不是很熟悉,请自行脑补winfom中grid的事件及sender和e是什么public void Run(object sender,Mao.MaoEventArgs e){Mao mao = (sender as Mao);Console.WriteLine($"{mao.Name}来了,老鼠逃跑了");}}class People{public void Wake(object sender, Mao.MaoEventArgs e){Mao mao = (sender as Mao);Console.WriteLine($"{mao.Name}的主人被惊醒了");}}class Program{static void Main(string[] args){Mao mao = new Mao("大脸猫");Laoshu laoshu = new Laoshu();People people = new People();//注册事件 这两种方式都可以mao.MaoEventHandler += new Mao.MaoDelegateHandler(laoshu.Run);mao.MaoEventHandler += people.Wake;//猫叫了一声 会自动调用注册过的方法
            mao.Miao();Console.Read();}}
View Code

分析:ok,这下面试的时候再也不怕面试官问你观察者模式相关知识了吧。。。

 

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

转载于:https://www.cnblogs.com/jdzhang/p/7397544.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/391614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python:在Pandas数据框中查找缺失值

How to find Missing values in a data frame using Python/Pandas如何使用Python / Pandas查找数据框中的缺失值 介绍&#xff1a; (Introduction:) When you start working on any data science project the data you are provided is never clean. One of the most common …

监督学习-回归分析

一、数学建模概述 监督学习&#xff1a;通过已有的训练样本进行训练得到一个最优模型&#xff0c;再利用这个模型将所有的输入映射为相应的输出。监督学习根据输出数据又分为回归问题&#xff08;regression&#xff09;和分类问题&#xff08;classfication&#xff09;&#…

微服务架构技能

2019独角兽企业重金招聘Python工程师标准>>> 微服务架构技能 博客分类&#xff1a; 架构 &#xff08;StuQ 微服务技能图谱&#xff09; 2课程简介 本课程分为基础篇和高级篇两部分&#xff0c;旨在通过完整的案例&#xff0c;呈现微服务的开发、测试、构建、部署、…

Tableau Desktop认证:为什么要关心以及如何通过

Woah, Tableau!哇&#xff0c;Tableau&#xff01; By now, almost everyone’s heard of the data visualization software that brought visual analytics to the public. Its intuitive drag and drop interface makes connecting to data, creating graphs, and sharing d…

约束布局constraint-layout导入失败的解决方案 - 转

今天有同事用到了约束布局&#xff0c;但是导入我的工程出现错误 **提示错误&#xff1a; Could not find com.Android.support.constraint:constraint-layout:1.0.0-alpha3** 我网上查了一下资料&#xff0c;都说是因为我的androidStudio版本是最新的稳定版导入这个包就会报这…

算法复习:冒泡排序

思想&#xff1a;对于一个列表,每个数都是一个"气泡 "&#xff0c;数字越大表示"越重 "&#xff0c;最重的气泡移动到列表最后一位&#xff0c;冒泡排序后的结果就是“气泡”按照它们的重量依次移动到列表中它们相应的位置。 算法&#xff1a;搜索整个列表…

前端基础进阶(七):函数与函数式编程

纵观JavaScript中所有必须需要掌握的重点知识中&#xff0c;函数是我们在初学的时候最容易忽视的一个知识点。在学习的过程中&#xff0c;可能会有很多人、很多文章告诉你面向对象很重要&#xff0c;原型很重要&#xff0c;可是却很少有人告诉你&#xff0c;面向对象中所有的重…

显示与删除使用工具

右击工具菜单栏中的空白处选择自定义 在弹出的自定义菜单中选择命令选项在选择想要往里面添加工具的菜单&#xff0c;之后在选择要添加的工具 若想要删除工具栏中的某个工具&#xff0c;在打开自定义菜单后&#xff0c;按住鼠标左键拖动要删除工具到空白处 例如 转载于:https:/…

js值的拷贝和值的引用_到达P值的底部:直观的解释

js值的拷贝和值的引用介绍 (Introduction) Welcome to this lesson on calculating p-values.欢迎参加有关计算p值的课程。 Before we jump into how to calculate a p-value, it’s important to think about what the p-value is really for.在我们开始计算p值之前&#xff…

监督学习-KNN最邻近分类算法

分类&#xff08;Classification&#xff09;指的是从数据中选出已经分好类的训练集&#xff0c;在该训练集上运用数据挖掘分类的技术建立分类模型&#xff0c;从而对没有分类的数据进行分类的分析方法。 分类问题的应用场景&#xff1a;用于将事物打上一个标签&#xff0c;通常…

无监督学习-主成分分析和聚类分析

聚类分析&#xff08;cluster analysis&#xff09;是将一组研究对象分为相对同质的群组&#xff08;clusters&#xff09;的统计分析技术&#xff0c;即将观测对象的群体按照相似性和相异性进行不同群组的划分&#xff0c;划分后每个群组内部各对象相似度很高&#xff0c;而不…

struts实现分页_在TensorFlow中实现点Struts

struts实现分页If you want to get started on 3D Object Detection and more specifically on Point Pillars, I have a series of posts written on it just for that purpose. Here’s the link. Also, going through the Point Pillars paper directly will be really help…

MySQL-InnoDB索引实现

联合索引提高查询效率的原理 MySQL会为InnoDB的每个表建立聚簇索引&#xff0c;如果表有索引会建立二级索引。聚簇索引以主键建立索引&#xff0c;如果没有主键以表中的唯一键建立&#xff0c;唯一键也没会以隐式的创建一个自增的列来建立。聚簇索引和二级索引都是一个b树&…

钉钉设置jira机器人_这是当您机器学习JIRA票证时发生的事情

钉钉设置jira机器人For software developers, one of the most-debated and maybe even most-hated questions is “…and how long will it take?”. I’ve experienced those discussions myself, which oftentimes lacked precise information on the requirements. What I…

vscode 标准库位置_如何在VSCode中使用标准

vscode 标准库位置I use Visual Studio Code as my text editor. When I write JavaScript, I follow JavaScript Standard Style.Theres an easy way to integrate Standard in VS Code—with the vscode-standardjs plugin. I made a video for this some time ago if youre …

IBM量子计算新突破:成功构建50个量子比特原型机

本文来自AI新媒体量子位&#xff08;QbitAI&#xff09;IBM去年开始以云计算服务的形式提供量子计算能力。当时&#xff0c;IBM发布了包含5个量子比特的计算机。在短短18个月之后&#xff0c;IBM周五宣布&#xff0c;将发布包含20个量子比特的计算机。 IBM还宣布&#xff0c;该…

小程序点击地图气泡获取气泡_气泡上的气泡

小程序点击地图气泡获取气泡Combining two colors that are two steps apart on the Color Wheel creates a Diad Color Harmony. This Color Harmony is one of the lesser used ones. I decided to cover it here to add variety to your options for colorizing visualizati…

PopTheBubble —测量媒体偏差的产品创意

产品管理 (Product Management) A couple of months ago, I decided to try something new. The MVP Lab by Mozilla is an 8-week incubator for pre-startup teams to explore product concepts and, over the 8 weeks of the program, ship a minimum viable product that p…

linux-Centos7安装nginx

首先配置linux环境&#xff0c;我这里是刚刚装好linux&#xff0c;所以一次性安装了一系列我需要到的环境&#xff1b; yum install pcre pcre-devel zlib zlib-devel openssl openssl-devel gd gd-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel e…

elasticsearch,elasticsearch-service安装

在Windows上安装Elasticsearch.zip 1 安装条件 安装需具备java 8或更高版本&#xff1b;官方的Oracle发行版&#xff0c;只需安装JDKElasticsearch的ZIP安装包——安装包地址 2 如何安装 Elasticsearch 傻瓜式的点下一步即可&#xff0c; java 注意环境变量配置 3 如何判断安装…