资讯专栏INFORMATION COLUMN

Java 设计模式 观察者模式

马忠志 / 282人阅读

摘要:实际上,设计模式就是通过面向对象的特性,将这些角色解耦观察者模式本质上就是一种订阅发布的模型,从逻辑上来说就是一对多的依赖关系。在添加一个观察者时,把被主题被观察者对象以构造函数的形式给传入了观察者。

每个角色都对应这一个类,比如观察者模式,观察者对应着观察者类,被观察者对应着被观察者类。实际上,设计模式就是通过面向对象的特性,将这些角色解耦

观察者模式本质上就是一种订阅 / 发布的模型,从逻辑上来说就是一对多的依赖关系。什么意思呢?好比是一群守卫盯着一个囚犯,只要囚犯一有异动,守卫就必须马上采取行动(也有可能是更新状态,本质上也是一种行动),那么守卫就是观察者,囚犯就是被观察者

在一个系统中,实现这种一对多的而且之间有一定关联的逻辑的时候,由于需要保持他们之间的协同关系,所以最简便的方法是采用紧耦合,把这些对象绑定到一起。但是这样一来,一旦有扩展或者修改的时候,开发人员所面对的难度非常大,而且很容易造成Bug。那么观察者模式就解决了这么一个问题,在保持一系列观察者和被观察者对象协同工作的同时,把解耦了它们

Coding

抽象观察者角色类

public interface Observer 
{
    // 更新接口
    public void update();
}

具体观察者角色类

public class ConcreteObserver implements Observer 
{
    // 观察者的状态
    private String observerState = "Initial";     // 观察者初始状态,会随着被观察者变化而变化
    private String name;                         // 观察者名称,用于标记不同观察者
    private Subject concreteSubject;
    
    // 构造观察者,并传入被主题对象,以及标识该观察者名称
    public ConcreteObserver(Subject concreteSubject, String name)
    {
        this.concreteSubject = concreteSubject;
        this.name = name;
        System.out.println("我是观察者" + name +", 我的状态是" + observerState);
    }
    
    // 观察者状态随主题主题改变
    public void update() 
    {
        observerState = concreteSubject.SubjectState;
        System.out.println("我是观察者" + name +", 我的状态是" + observerState);
    }
}

抽象主题角色类

import java.util.List;

public abstract class Subject 
{
    // 用来保存注册的观察者对象
    List list = null;
    String SubjectState;
    
    // 注册观察者对象
    public void attach(Observer observer){};
    
    //删除观察者对象
    public void detach(Observer observer){};
    
    // 通知所有注册的观察者对象
    public void nodifyObservers(String newState){};
}

具体主题角色类

import java.util.ArrayList;
import java.util.List;

public class ConcreteSubject extends Subject
{
    private List list = new ArrayList();
    public String SubjectState;


    // 注册观察者对象
    public void attach(Observer observer)
    {
        list.add(observer);
        System.out.println("Attached an observer");
    }
    
    //删除观察者对象
    public void detach(Observer observer){
        
        list.remove(observer);
    }
    
    // 通知所有注册的观察者对象
    public void nodifyObservers(String newState)
    {
        for(Observer observer : list)
        {
            observer.update();
        }
    }
}

客户端

public class Client 
{
    public static void main(String[] args) 
    {
        // 创建主题对象
        Subject concreteSubject = new ConcreteSubject();
        concreteSubject.attach(new ConcreteObserver(concreteSubject, "安倍晴明"));
        concreteSubject.attach(new ConcreteObserver(concreteSubject, "神乐"));
        concreteSubject.attach(new ConcreteObserver(concreteSubject, "源博雅"));
        
        concreteSubject.SubjectState = "结界突破!";
        concreteSubject.nodifyObservers(concreteSubject.SubjectState);
    }
}

运行结果

我是观察者安倍晴明, 我的状态是Initial
Attached an observer
我是观察者神乐, 我的状态是Initial
Attached an observer
我是观察者源博雅, 我的状态是Initial
Attached an observer
我是观察者安倍晴明, 我的状态是结界突破!
我是观察者神乐, 我的状态是结界突破!
我是观察者源博雅, 我的状态是结界突破!

观察者模式关键点

在主题(被观察者)中,定义了一个集合用来存放观察者,编写了注册attach()和移除detach()观察者的方法,这体现了一对多的关系,也提供了可以控制观察者的方式
关键点1:每个观察者需要被保存到主题(被观察者)的集合中,并且被观察者提供添加和删除的方式

观察者和被观察者之间的交互活动。在添加一个观察者时,把被主题(被观察者)对象以构造函数的形式给传入了观察者。最后主题(被观察者)执行nodifyObservers()方法,触发所有观察者的update()方法以更新状态
关键点2:被主题(被观察者)把自己传给观察者,当状态改变后,通过遍历或循环的方式逐个通知列表中的观察者

但这里有个问题,主题(被观察者)是通过构造函数参数的形式,传给观察者的,而观察者对象时被attach()到主题(被观察者)的list中
关键点3:虽然解耦了观察者和主题(被观察者)的依赖,让各自的变化不大影响另一方的变化,但是这种解耦并不彻底,没有完全解除两者之间的耦合

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

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

观察者模式,必然涉及到2委托和事件这两种类型

委托

委托就是可把方法当做另一个方法参数来传递,需要注意方法签名。委托可以看做是方法的抽象,也就是方法的“类”,一个委托的实例可以是一个或者多个方法。我们可以通过+=或者-=把方法绑定到委托或者从委托移除

事件

事件是一种特殊的委托。首先事件也是委托,只是在声明事件的时候,需要加上event,如果你用reflector去看一个事件,你会发现里面就3样东西,一个Add_xxxx方法,一个Remove_xxx方法,一个委托。和上面所定义主题(被观察者)时的注册attach()和移除detach()有些联系

.Net事件机制

实际上.Net的事件机制就是观察者模式的一种体现,并且是利用委托来实现。本质上事件就是一种订阅-发布模型也就是观察者模式,这种机制中包含2个角色,一个是发布者,一个是订阅者。发布者类也就类似于主题(被观察者),发布者类包含事件和委托定义,以及其之间的关系,发布者类的对象调用事件通知其他订阅者。而订阅者类也就类似于观察者,观察者接受事件,并且提供处理的逻辑。也就是说,订阅者对象(观察者)中的方法会绑定到发布者(被观察者)对象的委托中,一旦发布者(被观察者)中事件被调用,发布者(被观察者)就会调用委托中绑定的订阅者(观察者)的处理逻辑或者说是处理程序,这就是通过观察者模式实现的事件

观察者模式问答

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

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

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

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

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

委托是一种类型,事件是一种特殊的委托,观察者模式是一种设计模式,事件的机制是观察者模式的一种实现,其中订阅者和发布者通过委托实现协同工作

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66508.html

相关文章

  • Java 设计模式察者模式

    摘要:三内置观察者模式了解内置观察者模式包内包含最基本的类与接口,这和上面的接口与接口很类似。根据具体的需求,如果内置的观察者模式不能满设计,那么我们可以像刚开始那样自己实现一套观察者模式。参考资料设计模式 一、了解观察者模式 1.1 什么是观察者模式 观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新。 典型的问题比如报社,只要你是他...

    jsummer 评论0 收藏0
  • Java设计模式察者模式

    摘要:观察者模式的使用场景比如你微博关注了一个人,那么这个人发布的微博就会推送到你这。 Java设计模式之观察者模式 一直想写一篇学习观察者模式的总结没有契机,今天学习阻塞队列的原理时候看到在实现生产者消费者的时候用到了通知模式,就是所谓的观察者模式,正好顺便整理一下。 1. 简介 观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更...

    haitiancoder 评论0 收藏0
  • 我的Java设计模式-察者模式

    摘要:为了帮助灰太狼摆脱被老婆平底锅抽的悲剧,发起了解救灰太狼的行动,必须要知道观察者模式。持有观察者对象的集合。设计模式源码下载 相信大家都有看过《喜洋洋与灰太狼》,说的是灰太狼和羊族的斗争,而每次的结果都是灰太狼一飞冲天,伴随着一句我还会回来的......。为灰太狼感到悲哀,抓不到羊,在家也被老婆平底锅虐待。灰太狼为什么会这么背? 很简单,灰太狼本身就有暴露行踪的属性,羊咩咩就能知晓灰太...

    smartlion 评论0 收藏0
  • 自我理解-察者(Observer)模式

    摘要:观察者模式观察者模式也可以成为发布订阅模式,此模式是对象之间的模式,对象之间呈现一种一对多的关系。其中的一是被观察者,多是观察者,故被观察者不能产生多个对象,只能有一个对象供观察者观察,所以在写被观察者的时候,需要使用到单例模式。 观察者(Observer)模式 观察者(Observer)模式 也可以成为发布订阅模式,此模式是对象之间的模式,对象之间呈现一种一对多的关系。其中的一是被观...

    xuweijian 评论0 收藏0
  • JAVA设计模式-察者模式

    摘要:观察者模式涉及的角色主题一对多中的一,持有数据,当数据更新时,通知已注册的观察者观察者一对多中的多,接收主题数据做出响应举个栗子一位妈妈主题有两个孩子,取名为小爱和小冰观察者。 概念 观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象状态改变时,他的所有依赖者都会收到通知并自动更新。 showImg(https://segmentfault.com/img/bVbf0or?w...

    vvpale 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<