一、引言

相信猿友都大大小小经历过一些面试,其中有道经典题目,场景是猫咪叫了一声,老鼠跑了,主人被惊醒(设计有扩展性的可加分)。对于初学者来说,可能一脸懵逼,这啥跟啥啊是,其实博主当年也这感觉,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

面向对象编程思想-观察者模式相关推荐

  1. CoreJava学习第五课 --- 进入第二阶段:面向对象编程思想

    面向对象编程思想 1.面向过程 ​ 从计算机执行角度出发 ,代码执行过程核心为从程序的运行过程出发,构建编程思路,例: 哥德巴赫猜想 // 面向过程1 用户输入一个数n2 验证数字的正确性2.1 正确 ...

  2. 面向对象编程思想概览(一)类和对象

    一.简介 生活中有许多技巧值得我们在程序设计中模仿和借鉴.采用类的思想可以方便地把具有相同属性和方法归为一类,从而简化编程.本讲利用生活的常见示例,浅显通俗的语言,生动地介绍了面向对象编程中类与对象的 ...

  3. python完全支持面向对象编程思想_面向对象的编程思想和Python的类,访问和属性,继承...

    本文将从访问限制,属性,继承,方法重写这几个方面继续介绍面向对象的编程思想和Python类的继承. 复制代码 一.访问权限: Python中在类的内部定义属性和方法,在类的外部是可以直接调用或进行访问 ...

  4. 面向对象编程思想概览(三)继承

    一.简介 本讲以大家耳熟能详的<西游记>中的唐僧师徒四人为例,介绍了类的继承的概念和实现方法,总结了继承的特性和优点,帮助同学们理解面向对象编程中继承的用法,进而掌握面向对象程序设计的基本 ...

  5. 面向对象编程思想 以及类与对象

    一.面向对象编程思想 众所周知,我们常见的编程思想有面向过程和面向对象两种,像我们最基础的c语言,就是一种以过程为中心的编程思想,不关注具体的事件和对象而是针对于解决问题的思路和目标,这种编程思想由于 ...

  6. 基于STM32F103移植华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机

    华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机 因为在做华为LiteOS任务挂起和恢复需要使用到按键去触发任务挂起和恢复动作,因为我就萌发出使用状态机这种架构做一个按键检测触发.回想已 ...

  7. 面向对象编程思想及入门知识

    这几天在调程序,所以想写写自己对"面向对象编程"的一些理解,希望对打算入门计算机编程的同志们有所帮助.之前,好几个师弟问过我,C++与C有什么区别,学习面向对象语言需要掌握哪些基础 ...

  8. 第三章面向对象编程思想

    """ 编码规范: 类名首字母应以大写字母开头 类的成员/属性: 成员属性 实例化对象的属性: self.name=name 可以被访问,也可以在类的外部被修改 私有属性 ...

  9. Java学习——面向对象编程思想

    目录 一. 基本概念 二. 面向对象与面向过程的区别 三. 面向对象程序设计的类与对象 3.1 对象 3.2 类 四. 面向对象的四大特征 4.1 抽象 4.2 继承 4.3 封装 4.4 多态 1) ...

最新文章

  1. 拨开云雾见天日:剖析单机事务原理
  2. Python笔记总结(1)
  3. zookeeper3.4.6安装
  4. 语音计算矩形面积_【2020年第7期】螺旋折流板换热器质心当量矩形通用计算模型...
  5. phpcms 轮播图 (posid推荐位 )调用 - 代码篇
  6. NOIP2015 写后感
  7. c语言 linux常用函数,C语言常用函数
  8. tensorflow使用object detection实现目标检测超详细全流程(视频+图像集检测)
  9. 【深度优先搜索】牛客网:剪绳子
  10. 使用UITextField去自定义searchBar 【iOS】
  11. PAT 甲级 1003 Emergency 25分
  12. 凤凰 Remix android x86,主流 Android x86系统分享
  13. 【SemiDrive源码分析】【驱动BringUp】40 - Touch Panel 触摸屏调试 (Android侧)
  14. 电视盒子做文件共享服务器,【当贝市场】智能电视盒子和PC电脑文件共享教程...
  15. AndroidStudio不停地Indexing问题解决
  16. matlab实现手绘风格(简笔画风格、漫画风格)的曲线绘图
  17. android高斯模糊平均值,高斯模糊
  18. 微信分享到朋友圈的链接没有图片。开发工具中正常没有报错-解决方案
  19. 亲身经历:3天解决网站被百度网址安全中心拦截的方法
  20. 一张通往2030的“高铁票”:从无线网络到智能世界

热门文章

  1. 大学物理质点动力学思维导图_生理学 | 思维导图
  2. 微型计算机广告牌实验报告,微型计算机实验报告1资料.doc
  3. python recv_Python socket.recv方法代码示例
  4. 力扣合并两个有序数组
  5. java类编写sql_用JavaBean编写SQL Server数据库连接类
  6. 网络名称 转换 网络地址_网络地址转换| 计算机网络
  7. mcq 队列_MCQ | 密码学中作为IDEA,DES,AES,RSA的块密码
  8. ci框架 mysql 超时时间_mysql 字符集和校验规则( CHARSET amp; COLLATE)
  9. golang实现聊天室(四)
  10. C语言的atoi和C++的to_string