观察者模式——定义了对象之间的一对多依赖,这样一来,当一个对像改变状态时,它的所有依赖者都会收到通知并自动更新.
  从定义可以看出,OBSERVER(观察者)模式逻辑上需要两组对象来实现.首先它必需要有发布者(Publish),也可称为被观察的目标 (Subject)(习惯上都称它为目标Subject,后面我们都称它作目标Subject),另外就是订阅者(Subscribe),习惯上称为观察 者(Observer).一个目标对象对应多个观察者对象,目标对象发生变化时,所有在目标对象中注册的观察者对象会得到通知,自动更新自己.
  观察者模式UML图如下:
                        
  
  观察者模式的相关角色:
  1、抽象主体(Subject)角色:也 就是被关注的对象,是一对多关系中的那个“一”。它的相关信息的变化将会通知给订阅这个变化的观察者。主体角色把所有对观察考对象的引用保存在一个集合 (List,ArrayList.....)里,每个主体可能管理若干数量的观察者。抽象主体提供一个接口,可以增加和删除观察者对象,主体角色又叫做抽 象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
  2、抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主体的通知时更新自己。这个接口叫做更新接口(Update)。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
  3、具体主体(ConcreteSubject)角色:将有关状态存入具体现察者对象;在具体主体的内部状态改变时,给所有登记过的观察者发出通知。具体主体角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色通常用一个具体子类实现。
  4、具体观察者(ConcreteObserver)角色:存储与主体的状态自恰的状态。具体现察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主体的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主体对象的引用。具体观察者角色通常用一个具体子类实现。

下面,我们用代码来示例观察者模式。
 程序如下图:
                         
 一、观察者模式的基本思路
  1、抽象主体Subject


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyObserver
{
    //定义Subject抽象类,它是'ConcreteSubject'具体目标对象的基类
    //要实现Observer模式时,通常将数据对象作为目标(Subject),各个显示数据的对象作为观察者Observer
    //每一个观察者(Observer)通过调用目标(Subject)中的一个公有(public)方法,在他所感兴趣的数据中注册(registers)自己。
    //这样,当数据改变时,每一个目标(Subject)通过观察者(Observer)的接口发送更新通知。

abstract class Subject
    { 
        #region 定义一个List来装盛所有与此数据对象相联系的观察者Observer
        private List<Observer> _observers = new List<Observer>();
        #endregion

#region 附加或解除Observer功能(注册或注销功能)
        public void Attach(Observer observer)
        {
            _observers.Add(observer); //observer观察者在此数据对象中注册(registers)自己。
        }

public void Detach(Observer observer)
        {
            _observers.Remove(observer);//在此数据对象中取消注册,也即让对象变更时不用再通知此observer观察者
        }
        #endregion

#region 通知在_observers列表中的所有观察者
        public void Nofity()
        {
            //遍历观察者列表,按列表的名录逐一通知
            foreach (Observer o in _observers)
            {
                o.Update();
            }
        }
        #endregion
    }
 
}

2、具体主体ConcreteSubject


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyObserver
{
    //定义具体数据对象类,它继承自Subject抽象类
    class ConcreteSubject:Subject
    {
        #region SubjectState属性
        private string _subjectState;
        public string SubjectState
        {
            get { return _subjectState; }
            set { _subjectState = value; }
        }
        #endregion
    }
}

3、抽象观察者Observer


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyObserver
{
    #region 定义Observer抽象类,它是ConcreteObserver的基类
    abstract  class Observer
    {
        //定义一个用于发送更新通知的接口
        //这样,当数据改变时,每一个目标(Subject)通过观察者(Observer)的接口发送更新通知。
        public abstract void Update();
    }
    #endregion
}

4、具体观察者ConcreteObserver


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyObserver
{
    class ConcreteObserver:Observer 
    {
        private string _name;
        private string _observerState;

private ConcreteSubject _subject;
        public ConcreteSubject Subject
        {
            get { return _subject; }
            set { _subject = value; }
        }

#region 构造函数
        public ConcreteObserver(ConcreteSubject subject, string name)
        {
            this._subject = subject;
            this._name = name;
        }
        #endregion

#region 实现目标数据更新通知接口
        public override void Update()
        {
            _observerState = _subject.SubjectState;
            Console.WriteLine("观察者 {0} 收到的数据对象的新状态值是 {1}",_name,_observerState);

}
        #endregion

}
}

5、客户端代码 


            #region 基本思路示例
            Console.WriteLine("----------观察者模式基本思路示例--------");
            ConcreteSubject s = new ConcreteSubject(); //首先创建一个数据对象
            s.Attach(new ConcreteObserver(s, "X")); //向这个数据对象内注册三个观察者X,Y,Z
            s.Attach(new ConcreteObserver(s, "Y"));
            s.Attach(new ConcreteObserver(s, "Z"));

s.SubjectState = "ABC"; //改变数据对象的状态值
            s.Nofity(); //调用数据对象的通知功能来依次通知已经注册的观察者

Console.ReadKey();
            #endregion

 二、我的团长我的团使用观察者模式
 这里,我们让孟烦了在前哨望风,当他发现敌情时,他马上通知所有兄弟们准备战斗。这里,孟烦了就是具体主体ConcreteSubject,他的那些兄弟:要麻,迷龙,豆饼....等等都是具体观察者(ConcreteObserver)
  1、抽象主体Subject:Guard


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyObserver
{
    abstract class Guard
    {
        #region 定义一个List来收集所有需要通知到的其它士兵
        private List<Soldier> _soldiers = new List<Soldier>();
        #endregion

#region 附加或解除Observer功能(注册或注销功能)
        public void Attach(Soldier observer)
        {
            _soldiers.Add(observer); //observer观察者在此数据对象中注册(registers)自己。
        }

public void Detach(Soldier observer)
        {
            _soldiers.Remove(observer);//在此数据对象中取消注册,也即让对象变更时不用再通知此observer观察者
        }
        #endregion

#region 通知在_observers列表中的所有观察者
        public void Nofity()
        {
            //遍历观察者列表,按列表的名录逐一通知
            foreach (Soldier o in _soldiers)
            {
                o.Update();
            }
        }
        #endregion
    }
}

2、具体主体ConcreteSubject:ConcreteGurad


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyObserver
{
    class ConcreteGurad:Guard
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

#region FightInfo属性
        private string  _fightInfo;
        public string FightInfo
        {
            get { return _fightInfo; }
            set { _fightInfo = value; }
        }
        #endregion

public ConcreteGurad(string name)
        {
            this._name = name;
        }
    }
}

3、抽象观察者Observer:Soldier


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyObserver
{
    abstract  class Soldier
    {
        public abstract void Update();
    }
}

4、具体观察者ConcreteObserver:ConcreteSoldier


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyObserver
{
    class ConcreteSoldier:Soldier 
    {
        private string _observerState;
        private string _name;

private ConcreteGurad _subject;
        public ConcreteGurad Subject
        {
            get { return _subject; }
            set { _subject = value; }
        }

#region 构造函数
        public ConcreteSoldier(ConcreteGurad subject, string name)
        {
            this._subject = subject;
            this._name = name;
        }
        #endregion

#region 实现目标数据更新通知接口
        public override void Update()
        {
            _observerState = _subject.FightInfo ;
            Console.WriteLine("士兵 '{0}'  收到哨兵 '{1}' 的信号:{2}",_name,_subject.Name ,_observerState);

}
        #endregion
    }
}

5、客户端代码


            #region 我的团长我的团
            Console.WriteLine("----------我的团长我的团观察者模式示例--------");
            ConcreteGurad cg = new ConcreteGurad("孟烦了");
            ConcreteSoldier yaoma = new ConcreteSoldier(cg, "要麻");
            ConcreteSoldier sepigu = new ConcreteSoldier(cg, "蛇屁股");
            ConcreteSoldier doubing = new ConcreteSoldier(cg, "豆饼");
            ConcreteSoldier kangya = new ConcreteSoldier(cg, "康丫");
            ConcreteSoldier milong = new ConcreteSoldier(cg, "迷龙");
            ConcreteSoldier bula = new ConcreteSoldier(cg, "不辣");

cg.Attach(yaoma);
            cg.Attach(sepigu);
            cg.Attach(doubing);
            cg.Attach(kangya);
            cg.Attach(milong);
            cg.Attach(bula);

cg.FightInfo = "鬼子从右边摸上来了,大家准备歼灭他们.";
            cg.Nofity();
            Console.ReadKey();
            #endregion

程序运行后效果如下:

总结:
1、要点
 (1)抽象主体角色公开了自身的事件,可以给任意观察者订阅。
 (2)象观察者角色定义了统一的处理行为,在C#中使用事件-代理模式的话,统一的处理行为并不这么重要,有的时候甚至还会限制灵活性。
 (3)观察者往往只需要实现响应方法即可。
 (4)有多个主体角色、多个观察者角色交错,也可以一个类型是两个角色,主体也可以提供多个事件。从应用上来说观察者模式变化是非常多的。
2、优缺点
  观察者模式的优缺点
Observer模式的优点是实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,类别清晰,并抽象了更新接口,使得可以有各种各样不同的表示层(观察者)。
  但是其缺点是每个外观对象必须继承这个抽像出来的接口类,这样就造成了一些不方便,比如有一个别人写的外观对象,并没有继承该抽象类,或者接口不对,我们 又希望不修改该类直接使用它。虽然可以再应用Adapter模式来一定程度上解决这个问题,但是会造成更加复杂烦琐的设计,增加出错几率。
观察者模式的效果有以下几个优点:
(1)观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接 口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层 次。
(2)观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
观察者模式有下面的一些缺点:
(1)如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
(2)如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。
(3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。

转载于:https://www.cnblogs.com/smallfa/archive/2009/11/19/1606147.html

设计模式记--Observer Pattern观察者模式相关推荐

  1. Observer Pattern 观察者模式

    Observer Pattern (观察者模式) 定义: <设计模式>中对Observer模式的意图是这样描述的:"定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, ...

  2. Java Observer Pattern(观察者模式)

    当对象间存在一对多关系时,则使用观察者模式(Observer Pattern).比如,当一个对象被修改时,则会自动通知它的依赖对象.观察者模式属于行为型模式. 关键代码:在抽象类里有一个 ArrayL ...

  3. 设计模式(Design Pattern)

    简介 设计模式(Design Pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用.设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案.这些解决方案是众多软件开发人 ...

  4. Design Pattern: Observer Pattern

    1. Brief 一直对Observer Pattern和Pub/Sub Pattern有所混淆,下面打算通过这两篇Blog来梳理这两种模式.若有纰漏请大家指正. 2. Use Case 首先我们来面 ...

  5. C#设计模式之十六观察者模式(Observer Pattern)【行为型】

    C#设计模式之十六观察者模式(Observer Pattern)[行为型] 原文:C#设计模式之十六观察者模式(Observer Pattern)[行为型] 一.引言 今天是2017年11月份的最后一 ...

  6. 行为型设计模式(4)—— 观察者模式(Observer Pattern)

    文章目录 1.概述 2.实例 2.1 丑陋的设计 2.2 使用观察者模式 3.应用场景 4.优缺点 5.小结 参考文献 1.概述 使用设计模式可以提高代码的可复用性.可扩充性和可维护性.观察者模式(O ...

  7. 【23种设计模式】观察者模式(Observer Pattern)

    个人主页:金鳞踏雨 个人简介:大家好,我是金鳞,一个初出茅庐的Java小白 目前状况:22届普通本科毕业生,几经波折了,现在任职于一家国内大型知名日化公司,从事Java开发工作 我的博客:这里是CSD ...

  8. 设计模式-观察者模式(Observer Pattern)

    设计模式-观察者模式 观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应.在观察者模式中,发生改变的对象称为观 ...

  9. 设计模式 -行为型模式_ 观察者模式Observer Pattern 之 JDK内置的实现

    文章目录 概念 Code [主题] [观察者s] 观察者一 观察者二 [测试] 源码分析 java.util.Observable 目标类 java.util.Observer 观察者接口 notif ...

最新文章

  1. 阿里云https+nginx服务搭建
  2. SoundHound Inc. Programming Contest 2018[C. Ordinary Beauty]
  3. easyExcel 使用指南详解
  4. orb特征 稠密特征_一种基于ORB-SLAM2的双目三维稠密建图方法技术
  5. 计算机组成原理期末无选择题,计算机组成原理期末考试习题及答案精编(70页)-原创力文档...
  6. 201771010130 王志成《面向对象程序设计(java)》第十八周学习总结
  7. 微软认证考试考试 MCTS, MCITP, MCPD 享受9折优惠
  8. Odoo与ERP传统软件有什么不同?
  9. [C#]使用EasyHook注入ws2_32.dll,实现send和recv拦截数据封包
  10. 霍尼236主机说明书_霍尼韦尔236系统中文说明.DOC
  11. 非常赞的文章!告诉你一个你知其然却不知其所以然的硅谷
  12. 装机、资料库结构与文件备份方案
  13. 软件设计师真题知识点
  14. 世界杯要来了,先跟梅西来个热身吧_数字体验_新浪博客
  15. 怎样清理计算机c盘东西,怎样清理电脑c盘无用的东西(电脑c盘垃圾清理技巧)...
  16. 目标检测算法之CVPR 2019 Guided Anchoring
  17. [日推荐]『51好书推荐』专治假期综合症~
  18. 文件名称: 项目利用循环求和 、分数的累加、乘法表
  19. 如何在水晶报表里显示图象?
  20. 数据中台Citus集群压测报告

热门文章

  1. [html] 页面需要支持多语言,如果是你该怎么做?
  2. [html] 你有使用过ins标签吗?说说它的用途
  3. [css] 重置(初始化)css的作用是什么?
  4. 前端学习(2834):样式引入
  5. 前端学习(2404):表单验证总结
  6. 前端学习(2243)硅谷外卖项目展示
  7. 前端学习(1804):前端调试之列表伪类
  8. 第三十七期:如果你这样回答“什么是线程安全”,面试官都会对你刮目相看
  9. Qt定时器的精度问题
  10. AI知识点(1)--激活函数