设计模式之观察者模式

简介: 一、背景   随着工作时间的越来越长,发现对设计模式缺失的坏处越来越明显,但是当你知道某种设计模式的实现方式以后,你会发现,其实工作中早已经玩过这些东西,但是你之前并不知道它属于设计模式的一种,今天就先介绍一种设计模式:观察者模式,然后我们也手动实现观察者模式以加深印象。

一、背景

  随着工作时间的越来越长,发现对设计模式缺失的坏处越来越明显,但是当你知道某种设计模式的实现方式以后,你会发现,其实工作中早已经玩过这些东西,但是你之前并不知道它属于设计模式的一种,今天就先介绍一种设计模式:观察者模式,然后我们也手动实现观察者模式以加深印象。

二、模式介绍

  观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或者从属者(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

  应用场景:一个软件系统中常常要求在某一个对象的状态发生变化的时候,某些和它关联的其他的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计时需要使这些低耦合的对象之间能够维持行为的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。

三、观察者模式结构和组成

  

  由上图可知,观察者模式所涉及的角色有:

  1.抽象主题角色(Subject):抽象主题角色把所有对观察者对象的引用保存在一个集合(比如Vector)里,然后每个主题都可以有任何数量的观察者。抽象主题提供的接口有:增加观察者对象、删除观察者对象、通知所有的观察者对象、获取观察者数量、设置改变。

  2.具体主题角色(ConcreteSubject): 将有关状态存入具体主题对象,在具体主题的内部状态改变时,给所有注册过的观察者发送通知。

  3.抽象观察者角色(Observer):为所有的具体观察者定义一个接口,订阅的主题改变时更新自己,这个接口叫做更新接口。

  4.具体观察者角色(ConcreteObserver):存储与主题自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态向协调。如有需要,具体观察者角色可以保持一个指向具体主题对象的引用。

四、代码实现

1.抽象观察者角色Observer.java接口

package com.hafiz.www.observerPattern;

/**
 * Desc:观察者接口
 * Created by hafiz.zhang on 2017/7/27.
 */
public interface Observer {

    /**
     * 已订阅的主题发生改变时调用此方法来更新自己
     *
     * @param obj 当前正在发生改变的可观察者对象
     *
     * @param args 参数
     */
    void update(Observable obj, Object args);
}

2.抽象主题角色Observable.java类

package com.hafiz.www.observerPattern;

import java.util.Vector;

/**
 * Desc: 抽象可被观察者类
 * Created by hafiz.zhang on 2017/7/27.
 */
public abstract class Observable {

    private Vector<Observer> observers;     // 已订阅的观察者集合
    private boolean changed = false;        // 状态

    public Observable() {
        observers = new Vector<>();
    }

    public synchronized void addObserver(Observer observer) {
        if (observer == null) {
            throw new NullPointerException();
        }
        if (!observers.contains(observer)) {
            observers.addElement(observer);
        }
    }

    public synchronized void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public synchronized void setChanged() {
        changed = true;
    }

    public synchronized void clearChanged() {
        changed = false;
    }

    public void notifyObservers(Object args) {
        Observer[] observersLocal;
        synchronized (this) {
            if (!changed) {
                return;
            }
            observersLocal = new Observer[observers.size()];
            observersLocal = observers.toArray(observersLocal);
            clearChanged();
        }
        for (int i = 0; i < observersLocal.length; i++) {
            observersLocal[i].update(this, args);
        }
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public synchronized void deleteAllObserver() {
        observers.removeAllElements();
    }

    public synchronized int countObservers() {
        return observers.size();
    }
}

3.具体观察者实现类ConcreteObserver.java类

package com.hafiz.www.observerPattern;

/**
 * Desc:具体观察者实现类
 * Created by hafiz.zhang on 2017/7/27.
 */
public class ConcreteObserver implements Observer {
    private String status;

    @Override
    public void update(Observable obj, Object args) {
        System.out.println("Observable:" + obj.getClass().getName() + " status has changed");
        this.status = (String)args;
        System.out.println("After changed ConcreteObserver`s status is : " + status);
    }
}

4.具体主题实现类ConcreteSubject.java类

package com.hafiz.www.observerPattern;

/**
 * Desc:具体主题实现类
 * Created by hafiz.zhang on 2017/7/27.
 */
public class ConcreteSubject extends Observable {
    private String status = "originalStatus";

    public ConcreteSubject(Observer observer) {
        // 注册观察者
        addObserver(observer);
    }

    public void changeStatus(String status) {
        System.out.println("Before changed ConcreteSubject`s status is : " + this.status);
        this.status = status;
        System.out.println("After changed ConcreteSubject`s status is : " + this.status);
        setChanged();
        notifyObservers(this.status);
    }
}

5.单元测试类

package com.hafiz.www;

import com.hafiz.www.observerPattern.ConcreteObserver;
import com.hafiz.www.observerPattern.ConcreteSubject;
import org.junit.Test;

/**
 * Desc:设计模式demo单元测试类
 * Created by hafiz.zhang on 2017/7/27.
 */
public class DesignPatternTest {

    @Test
    public void testObserverPattern() {
        ConcreteObserver observer = new ConcreteObserver();
        ConcreteSubject subject = new ConcreteSubject(observer);
        subject.changeStatus("new Status");
    }
}

6.运行结果截图:

7.说明和扩展

  在观察者模式中,其实又细分为推模型和拉模型,所谓推模型是指,在主题类发生改变的时候,调用观察者update()方法直接把数据通过args参数传过去,不管观察者是否真的需要;而拉模型是调用update()方法时,把自己传递给观察者,观察者需要什么数据,它自己从主题对象中获取。在我看来拉模型更加的易于扩展。

  其实,在java.util包里面,jdk默认也给我们提供了这样实现,其中Observer.java是观察者抽象类,Observable.java是主题抽象类,我们可以拿来使用,其中的实现和本文的差别不大。使用时,我们只需要基于这两个类进行实现就可以了很简单。推荐使用!

  文中代码github地址:https://github.com/hafizzhang/DesignPattern.git

五、总结

  通过本文,我们就了解了什么叫观察者模式,以及怎么实现该模式,以及该模式的特点。以后的工作中,我们很好的结合具体场景来使用,可以说收获满满!喜欢请点赞。

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