设计模式:观察者模式(Observer)

简介: 定义对象见的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者模式的角色 1. 抽象主题角色(Subject):把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。

定义对象见的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

这里写图片描述

观察者模式的角色
1. 抽象主题角色(Subject):把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
2. 具体主题角色(ConcreteSubject):在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
3. 抽象观察者角色(Observer):为所有的管擦着定义一个接口,在得到主题的通知更新自己。
4. 具体观察者角色(ConcreteObserver):该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态和主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保持一个指向具体主题角色的引用。


举个简单案例:
1 抽象观察者角色(Observer):

public interface Observer
{
    public void update(String str);
}

2 抽象主题角色(Subject)

public abstract class Subject
{
    private List<Observer> list = new ArrayList<>();

    public void attach(Observer observer)
    {
        list.add(observer);
    }

    public void detach(Observer observer)
    {
        list.remove(observer);
    }

    public void notifyObservers(String str)
    {
        int len = list.size();
        for(int i=0;i<len;i++)
        {
            list.get(i).update(str);
        }
    }
}

3 具体主题角色(ConcreteSubject)

public class ConcreteSubject extends Subject
{
    private String subjectState;

    public String getState(){
        return subjectState;
    }

    public void setState(String newState)
    {
        this.subjectState = newState;
        System.out.println("主题状态为: "+subjectState);
        this.notifyObservers(subjectState);
    }
}

4 具体观察者角色(ConcreteObserver)

public class ConcreteObserver implements Observer
{
    private String observerState;
    @Override
    public void update(String state)
    {
        observerState = state;
        System.out.println("状态为: "+observerState);
    }
}
  1. 测试代码:
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer = new ConcreteObserver();
        subject.attach(observer);
        subject.setState("new State");

输出结果:

主题状态为: new State
状态为: new State

推模型和拉模型
在观察者模式中,又分为推模型和拉模型两种方式。
1. 推模型:主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
2. 拉模型:主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。

将上面的代码修改一下,变为拉模型案例:
1 抽象观察者角色Observer2,通常是把主题对象当做参数传递

public interface Observer2
{
    public void update(Subject2 subject);
}

2 具体观察者角色

public class ConcreteObserver2 implements Observer2
{
    private String observerState;
    @Override
    public void update(Subject2 subject)
    {
        observerState = ((ConcreteSubject2)subject).getState();
        System.out.println("状态为: "+observerState);
    }
}

3 抽象主题角色

public abstract class Subject2
{
    private List<Observer2> list = new ArrayList<>();

    public void attach(Observer2 observer)
    {
        list.add(observer);
    }

    public void detach(Observer2 observer)
    {
        list.remove(observer);
    }

    public void notifyObservers()
    {
        int len = list.size();
        for(int i=0;i<len;i++)
        {
            list.get(i).update(this);
        }
    }
}

4 具体主题角色

public class ConcreteSubject2 extends Subject2
{
    private String subjectState;

    public String getState(){
        return subjectState;
    }

    public void setState(String newState)
    {
        this.subjectState = newState;
        System.out.println("主题状态为: "+subjectState);
        this.notifyObservers();
    }
}

测试代码:

        ConcreteSubject2 subject = new ConcreteSubject2();
        Observer2 observer = new ConcreteObserver2();
        subject.attach(observer);
        subject.setState("new State");

输出结果:(同上一个案例)

两种模式比较

  1. 推模型假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己取按需要取值。
  2. 推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是主题对象本身,这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。

优缺点
优点:
1. Subject和Observer之间是松耦合的,分别可以各自独立改变。
2. Subject在发送广播通知的时候,无需指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
缺点:
1. 松耦合导致代码关系不明显,有时可能难以理解
2. 如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。

适用场景
1. 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态改变。
2. 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。

JDK中的观察者模式:
java.util.EventListener
javax.servlet.http.HttpSessionBindingListener
javax.servlet.http.HttpSessionAttributeListener
javax.faces.event.PhaseListener


参考资料
1. 《23种设计模式
2. 《细数JDK里的设计模式
3. 《《JAVA与模式》之观察者模式

目录
相关文章
|
3月前
|
设计模式 监控 安全
设计模式 | 观察者模式
设计模式 | 观察者模式
18 0
|
3月前
|
设计模式 前端开发 数据中心
设计模式之观察者模式
设计模式之观察者模式
|
2月前
|
设计模式 前端开发 JavaScript
观察者模式 vs 发布-订阅模式:两种设计模式的对决!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
17天前
|
设计模式 监控 Java
设计模式 - 观察者模式(Observer):Java中的战术与策略
【4月更文挑战第7天】观察者模式是构建可维护、可扩展系统的关键,它在Java中通过`Observable`和`Observer`实现对象间一对多的依赖关系,常用于事件处理、数据绑定和同步。该模式支持事件驱动架构、数据同步和实时系统,但需注意避免循环依赖、控制通知粒度,并关注性能和内存泄漏问题。通过明确角色、使用抽象和管理观察者注册,可最大化其效果。
|
1月前
|
设计模式 存储 Java
【设计模式】观察者模式
【设计模式】观察者模式
|
3月前
|
设计模式 Java Spring
设计模式之观察者模式
设计模式之观察者模式
26 0
|
3月前
|
设计模式 算法 自动驾驶
常见的设计模式(模板与方法,观察者模式,策略模式)
随着时间的推移,软件代码越来越庞大,随着而来的就是如何维护日趋庞大的软件系统。在面向对象开发出现之前,使用的是面向过程开发来设计大型的软件程序,面向过程开发将软件分成一个个单独的模块,模块之间使用函数进行组合,最后完成系统的开发,每次需要修改软件,如果不涉及好各个模块的关系,就会导致软件系统难以维护,从而导致软件变得不可使用。面向对象方法用对象模拟问题域中的实体,以对象间的联系刻画实体间联系
63 2
|
3月前
|
设计模式 前端开发 NoSQL
聊聊Java设计模式-观察者模式
观察者模式(Observer Design Pattern),也叫做发布订阅模式(Publish-Subscribe Design Pattern)、模型-视图(Model-View)模式、源-监听器(Source-Listener)模式、从属者(Dependents)模式。指在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。
66 0
聊聊Java设计模式-观察者模式
|
3月前
|
设计模式 消息中间件 Go
Golang设计模式——23观察者模式
Golang设计模式——23观察者模式
23 0
|
3月前
|
设计模式 JavaScript 前端开发
【设计模式】之观察者模式
观察者模式是一种常用的设计模式,在前端开发中有广泛应用。它通过定义一种一对多的依赖关系,实现了对象之间的解耦和灵活性。通过使用观察者模式,可以实现事件处理、数据绑定、响应式系统等功能。然而,需要根据具体情况权衡使用观察者模式所带来的优缺点。
25 0