Head First设计模式之观察者模式

简介: 一、定义 观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。 有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

一、定义

观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

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

观察者模式是写松耦合代码的必备模式。

 

二、结构

三、实现

//被观察者
 
public interface IObject
    {
 
        IList<IMonitor> ListMonitor { get; set; } //定义观察者集合,因为多个观察者观察一个对象,所以这里用集合
        string SubjectState { get; set; }        //被观察者的状态
     
 
        void AddMonitor(IMonitor monitor);  //添加一个观察者
 
        void RemoveMonitor(IMonitor monitor); //移除一个观察者
 
        void SendMessage(); //向所有观察者发送消息
 
    }
    public class Subject : IObject
    {
 
 
        private IList<IMonitor> listMonitor = new List<IMonitor>();
 
        public string SubjectState //被观察者的状态
        {
            get;set;
        }
 
 
        public IList<IMonitor> ListMonitor //实现具体的观察者列表属性
        {
            get { return listMonitor; }
            set { listMonitor = value; }
        }
 
        public void AddMonitor(IMonitor monitor)  //实现具体的添加观察者方法
        {
            listMonitor.Add(monitor);
        
        }
 
        public void RemoveMonitor(IMonitor monitor) //实现具体的移除观察者方法
        {
           
            listMonitor.Remove(monitor);
        }
 
        public void SendMessage()    //实现具体的发送消息方法
        {
            foreach (IMonitor m in listMonitor)  //发送给所有添加过的观察者,让观察者执行update方法以同步更新自身状态
            {
                m.Update();
            }
        }
    }
 
 
//观察者
 
  public interface IMonitor //定义观察者接口
    {
        void Update(); 
    }
 
 
    public class Monitor : IMonitor   //实现具体观察者
    {
        private string monitorState="Stop!";    //观察者初始状态,会随着被观察者变化而变化
        private string name;            //观察者名称,用于标记不同观察者
        private IObject subject;        //被观察者对象
 
 
 
        public Monitor (IObject subject, string name)  //在构造观察者时,传入被观察者对象,以及标识该观察者名称
        {
            this.subject = subject;
            this.name = name;
            Console.WriteLine("我是观察者{0},我的初始状态是{1}", name, monitorState);
 
 
        }
 
 
        public void Update()                           //当被观察者状态改变,观察者需要随之改变
        {
            monitorState = subject.SubjectState;
            Console.WriteLine("我是观察者{0},我的状态是{1}", name, monitorState);
 
        }
    }
 
 
//前端调用
 
   static void Main(string[] args)
        {
 
            IObject subject = new Subject();
            subject.AddMonitor(new Monitor(subject, "Monitor_1"));
            subject.AddMonitor(new Monitor(subject, "Monitor_2"));
            subject.AddMonitor(new Monitor(subject, "Monitor_3"));
 
            subject.SubjectState = "Start!";
            subject.SendMessage();
 
            Console.Read();
        }
    }

 

四、适用场景

1 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。

2 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

 

五、优缺点

  优点

    观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。

  缺点

    依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。

六、模式引申

  应用C#中的事件委托来彻底解除通知者和观察者之间的耦合。

  1 关于委托的定义:委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法有相同的行为。委托方法可以像其它任何方法一样,具有参数和返回值。委托可以看作是对函数(方法)的的抽象,是函数的“类”,委托的实例代表一个(或多个)具体的函数,它可以是多播的。

  2 关于事件:事件基于委托,为委托提供了一种发布/订阅机制。事件的订阅与取消与我们刚才讲的观察者模式中的订阅与取消类似,只是表现形式有所不同。在观察者模式中,订阅使用方法Attach()来进行;在事件的订阅中使用“+=”。类似地,取消订阅在观察者模式中用Dettach(),而事件的取消用“-=”。

 

七、答疑

1. 在普通的观察者模式中,解耦并不彻底,那么在事件的发布订阅模型中,解耦彻底吗?为什么?

答案是肯定的。因为在事件中,订阅者和发布者之间是通过把事件处理程序绑定到委托,并不是把自身传给对方。所以解决了观察者模式中不完全解耦的问题。这也是关键点之四

2. 通过委托绑定方法来实现观察者模式,会不会有什么隐患?

有的,通过+=去把方法绑定到委托,很容易忘记-=。如果只绑定不移除,这个方法会一直被引用。我们知道GC去回收的时候,只会处理没有被引用的对象,只要是还被引用的对象时不会被回收掉的。所以如果在长期不关闭的系统中(比如监控系统),大量的代码使用+=而不-=,运行时间长以后有可能会内存溢出。

3. 事件,委托,观察者模式之间的关系

这个上面已经提到了,委托时一种类型,事件是一种特殊的委托,观察者模式是一种设计模式,事件的机制是观察者模式的一种实现,其中订阅者和发布者通过委托实现协同工作。

好的,最后我们还是来归纳一下观察者模式的关键点

一、每个观察者需要被保存到被观察者的集合中,并且被观察者提供添加和删除的方式。

二、被观察者把自己传给观察者,当状态改变后,通过遍历或循环的方式逐个通知列表中的观察者。

三、虽然解耦了观察者和被观察者的依赖,让各自的变化不大影响另一方的变化,但是这种解耦并不是很彻底,没有完全解除两者之间的耦合。

四、在事件中,订阅者和发布者之间是通过把事件处理程序绑定到委托,并不是把自身传给对方。所以解决了观察者模式中不完全解耦的问题

注意点:在使用委托绑定方法时,需要注意移除方法,否则可能会造成内存溢出。

建议:不能理解事件和委托的同学,好好地把事件和委托看一看,并且自己写点代码加深印象。

 

参考:

http://blog.jobbole.com/109845/

http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html

 

欢迎阅读本系列文章:Head First设计模式之目录

 

相关文章
|
28天前
|
设计模式 监控 Java
Kotlin - 改良设计模式 - 观察者模式
Kotlin - 改良设计模式 - 观察者模式
51 3
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
17天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
19天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
36 1
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
28 3
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
35 9
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
35 2
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
3月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
1月前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###