学C#之设计模式系列笔记(2)观察者模式

一、借鉴说明

1.《Head First Design Patterns》(中文名《深入浅出设计模式》)

2.维基百科,观察者模式,https://zh.wikipedia.org/wiki/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F

3.MSDN,event(C#参考),https://msdn.microsoft.com/zh-cn/library/8627sbea.aspx

二、观察者模式

  • 基础知识

提供一个被观察者(数据库、通知中心等),多个观察者注册到该被观察者上,当观察者关心的数据改变的时候,被观察者会通知各个观察者。被观察者可以将数据主动地传给观察者(推方式)或者观察者在接到通知后主动向被观察者获取数据(拉方式)。

  • 具体例子

现如今,用户可以通过邮箱订阅各式各样的周刊,而负责这些周刊的出版社会定时地将周刊发送到用户的邮箱,这些周刊的版面都是分为两种,一种是头条(即出版社特别推荐给用户的,有详尽说明的内容),一种是链接群(就是一些摘要的、附有超链接的内容,用户如果有兴趣的话,可以进而点击超链接了解详情)。如果用户想要每周获得指定出版社的周刊,就需要首先在该出版社上进行注册,如果想订阅多个出版社的周刊,则需要在各个出版社上都进行注册。当然,用户都有权利取消订阅。

这里,用户User就是观察者Observer,出版社Press就是被观察者Observable,User订阅了某Press的周刊就是注册register,User取消订阅就是注销remove,定时发送周刊就是通知notify,而头条就是推方式push,即Press主动推送数据给User的情况,链接群就是拉方式pull,即接到通知后,User主动向Press获取数据的情况。因此,Press就有了registerObserver函数(添加观察者)、removeObserver函数(移除观察者)、updateImportantContent函数("推方式"推送头条)、updateHyperlink函数("拉方式"发送链接),User就有了notifyPush函数("推方式"获得头条,各个User对头条的处理方式不尽相同)、notifyPull函数("拉方式"获得链接群,各个User对链接群的处理方式不尽相同)。User可以调用Press的registerObserver函数订阅周刊,调用removeObserver函数取消订阅周刊。UML如图所示。

如上图所示,为了保证Press的封装性,具体的是指updateImportantContent函数和updateHyperlink函数私有,以确保Press才有发出通知的权利(如若没有确保封装性,假设有一个心怀不轨的作者,只想让自己的作品独占整个周刊,那么他完全可能调用updateImportantContent函数和updateHyperlink函数达成自己的目的),但是这样,耦合度又太高了,所以笔者认为:针对C#,推荐使用event关键字实现观察者模式,具体的实现见下文。

  • 什么时候可以考虑使用观察者模式

当一个对象依赖另一个对象的数据变化的时候,或者子线程异步操作完成后通知主线程的时候,可以考虑使用观察者模式。

  • 具体的C#实现

设计模式(C#)的相关代码我都放在git上:https://github.com/MGKING3/DesignPatternsUseCSharp

我使用的是VS2015,是整一个项目,下载即可以用,不时更新。

如果使用不了git的话,百度云也是可以下载的,地址:http://pan.baidu.com/s/1bp7Txuf

望互相学习,谢谢

  • 相关OO原则

1.封装原则

2.多用组合(has-a),少用继承(is-a)

3.尽量"面向接口"

4.追求"松耦合"

时间: 2024-10-05 04:10:30

学C#之设计模式系列笔记(2)观察者模式的相关文章

菜鸟学设计模式系列笔记之Prototype模式(原型模式)

菜鸟学设计模式系列笔记之Prototype模式: Intent: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 Motivation:以一个已有的对象作为原型,通过它来创建新的对象. 在增加新的对象的时候,新对象的细节创建工作由自己来负责,从而使新对象的创建过程与框架隔离开来. 应用场景: (1)当一个系统应该独立于它的产品创建.构成和表示时 (2)当要实例化的类是在运行时刻指定时,例如动态加载 (3)为了避免创建一个产品类层次平行的工厂类层次时 (4)当一个类的实例只能有几个

菜鸟学设计模式系列笔记之创建型模式简介

设计模式是"封装变化"方法的最佳阐释 无论是创建型模式.结构型模式.还是行为型模式,归根结底都是寻找软件中可能存在的"变化",然后利用抽象的方式对这些变化进行封装. 由于抽象没有具体的实现,就代表了一种无限可能性,使得其扩展成为了可能. 经典设计模式都是在寻找软件中的可能变化,并封装这些变化. 封装通常的理解:将数据(属性)和对数据的操作(方法)放到一个程序单元(类)中,从而使得概念上相关的数据和操作在编程语言上相关:正确的理解:信息隐藏--隐藏细节,对对象内部细节

菜鸟学设计模式系列笔记之建造者模式(Builder模式)

提供一种"封装机制"来隔离出"复杂对象的各个部分"的变化. 从而保持系统中的"稳定构建算法"不随需求变化而变化.----建造者模式 建造模式是对象的创建模式 建造模式可以将一个产品的内部表象与产品的生成过程分割开来, 从而可以是一个建造过程生成具有不同的内部表象的产品对象. Intent : 将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 Motivation: 在复杂对象的构造过程中,允许同样的构造过程能够加入新的被

菜鸟学设计模式系列笔记之抽象工厂模式

抽象工厂模式(Abstract Factory模式): (1)Intent:提供一个创建一系列相关后相互依赖对象的接口,而无需指定它们具体的类-客户端不必指定产品的具体类型,创建多个产品族中的产品对象 (2)Motivation :为保证视感风格标准间的可移植性,应用不应该为一个特定的视感外观硬编码它的窗口组件.在整个应用中实例化特定的视感风格的窗口组建类将使得使得以后很难改变视感的风格. 抽闲工厂模式面对的是多个产品等级结构的系统设计. 工厂方法模式针对的是一个产品等级结构: 抽象工厂模式需要

菜鸟学设计模式系列笔记之单例设计模式(Singleton模式)

特殊的类: (1)类和它的实例间一般是一对多的关系.对大多数的类而言,都可以创建多个实例. 在需要这些实例时创建它们,在这些实例不再有用时删除它们.这些实例的来去伴随着内存的分配和归还. (2)但是有一些类,应该只有一个实例. 这个实例似乎应该在程序启动时被创建出来,且只有在程序结束时才被删除. Intent : 一个类仅有一个实例,自行实例化并向整个系统提供一个访问它的全局访问点 Motivation : 对于一些类来说,只有一个实例是很重要的 Singleton (1)定义一个Instanc

菜鸟学设计模式系列笔记之工厂方法模式

工厂方法模式(Factory Method): Alias :virtual constructory 虚构造器 Intent: 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使一个类的实例化延迟到其子类. Motivation:一个框架使用抽象类定义和管理对象之间的关系.这个框架负责去创建这些对象. 工厂方法模式是类的创建模式,又叫做虚拟构造子模式(Virtual Constructor)或者多态性(Polymorphic Factory)工厂模式 工厂方法

菜鸟学设计模式系列笔记之适配器模式(adapter模式)

一.结构模式简介: 在面向对象软件系统中,每个类都承担了一定的职责,它们可以相互协作,实现一些复杂的功能 结构型模式关注的是如何将现有类或对象组织在一起形成更加强大的结构 不同的结构型模式从不同的角度来组合类和对象 1.结构模式描述如何将类或者对象结合在一起形成更大的结构 (1)类的结构模式:类的结构模式使用继承把类.接口等组合在一起,以形成更大的结构.当一个类从父类继承并实现某接口时,这个新的类就把父类的结构和接口的结构组合起来.类的结构模式是静态的. (2)对象的结构模式:对象的结构模式描述

设计模式系列之四:观察者模式

前言 观察者模式是属于设计模式中的行为型模式,所谓行为型就是指对象的动作发生改变,比如方法以及状态.那么观察者模式是一种什么模式呢?说白了,观察者模式解决的一对多的依赖关系,当一个对象的状态发生改变的时候,其他依赖此对象的对象会得到通知并且做出相应的改变.但从定义上还是很难理解.我们可以从一个简单的例子中更深地去体会观察者模式. 问题背景 某公司的两名职员在主管离开办公室后,一个在看股票,一个在玩游戏.公司有一个前台,该两名职员让前台当主管回来的时候通知他们不让主管看到他们在干其他的事. 编码实

Java设计模式学习笔记(观察者模式)

观察者模式说起来很简单,就是一个订报纸的模式.但是实际上这部分我觉得还是很有意思的,<Head First设计模式>里还有一些还没看完,也是因为理解的不够深吧. 观察者模式会包含两个组件:观察者和主题. 这段代码是主题的接口: package obeserver; public interface Subject { public void registerObserver(Observer observer); public void removeObserver(Observer obse