设计模式:观察者模式

15 篇文章 0 订阅
9 篇文章 0 订阅

1.简介

–《百度百科 观察者模式》

观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用。 [1]

观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

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

–《Head First设计模式(中文版)》

观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

2.具体操作及实现

举例:新闻报道,由记者获取最新新闻,相关新闻媒体发布新闻

整体结构如下所示:

在这里插入图片描述

主题类(被观察者)Subject 接口:

package cn.shentianlan.studytest.designmode.observer.example;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 主题(被观察者)
 * @date 2021/10/12 22:20
 */
public interface Subject {
    /**
     * 注册观察者
     * @param observer
     */
    void registerObserver(Observer observer);

    /**
     * 移除观察者
     * @param observer
     */
    void removeObserver(Observer observer);

    /**
     * 通知观察者
     */
    void notifyObserver();

}

观察者 Observer:

package cn.shentianlan.studytest.designmode.observer.example;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 观察者
 * @date 2021/10/12 22:21
 */
public interface Observer {
    void update(String news);
}

主体数据 被观察者对象 记者 Reporter

package cn.shentianlan.studytest.designmode.observer.example;

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

/**
 * @author 渊蓝
 * @version 1.0
 * @description 记者
 * @date 2021/10/12 22:23
 */
public class Reporter implements Subject {

    //观察者队列
    private List<Observer> observerList;

    public Reporter() {
        this.observerList = new ArrayList<>();
    }

    private String news;

    @Override
    public void registerObserver(Observer observer) {
        if (!observerList.contains(observer)){
            observerList.add(observer);
        }
    }

    @Override
    public void removeObserver(Observer observer) {
        if (!observerList.isEmpty() ){
            observerList.remove(observer);
        }
    }

    @Override
    public void notifyObserver() {
        if (!observerList.isEmpty()){
            observerList.forEach(observer -> {
                observer.update(news);
            });
        }
    }


    public String getNews() {
        return news;
    }

    public void setNews(String news) {
        this.news = news;
        notifyObserver();
    }
}

观察者对象 PeoplesNetwork XinHuaNet

package cn.shentianlan.studytest.designmode.observer.example;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 人民网
 * @date 2021/10/12 22:31
 */
public class PeoplesNetwork implements Observer{

    public PeoplesNetwork(Subject subject) {
        subject.registerObserver(this);
    }

    @Override
    public void update(String news) {
        System.out.println("人民网:"+news);
    }
}
package cn.shentianlan.studytest.designmode.observer.example;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 新华网
 * @date 2021/10/12 22:34
 */
public class XinHuaNet implements Observer {

    public XinHuaNet(Subject subject) {
        subject.registerObserver(this);
    }

    @Override
    public void update(String news) {
        System.out.println("新华网:"+news);
    }
}

测试 ObserverTest:

package cn.shentianlan.studytest.designmode.observer.example;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 观察者模式测试类
 * @date 2021/10/12 22:37
 */
public class ObserverTest {
    public static void main(String[] args) {
        Reporter reporter = new Reporter();
        PeoplesNetwork peoplesNetwork = new PeoplesNetwork(reporter);
        XinHuaNet xinHuaNet = new XinHuaNet(reporter);

        reporter.setNews("记者小蓝报道:母猪正在试图爬树");

        //移除人民网观察者
        reporter.removeObserver(peoplesNetwork);

        reporter.setNews("记者小李报道:最近有台风登陆,请市民出行注意安全");
    }
}

结果:

人民网:记者小蓝报道:母猪正在试图爬树
新华网:记者小蓝报道:母猪正在试图爬树
新华网:记者小李报道:最近有台风登陆,请市民出行注意安全

3 Java内置的观察者对象解析

使用Java内置的Observable(被观察者)和Observer(观察者)对上面的案例进行修改(注意引用的包是java.util中的)

主体数据 被观察者对象 记者 Reporter

package cn.shentianlan.studytest.designmode.observer.javaExample;

import java.util.Observable;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 记者
 * @date 2021/10/12 23:00
 */
public class Reporter extends Observable {
    private String news;

    public void setNews(String news) {
        this.news = news;
        //setChanged()方法用来标记状态已经改变的事实,好让notifyObservers()知道当它被调用时应该更新观察者。
        setChanged();
        notifyObservers(news);
    }
}

观察者对象 PeoplesNetwork XinHuaNet

package cn.shentianlan.studytest.designmode.observer.javaExample;

import java.util.Observable;
import java.util.Observer;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 人民网
 * @date 2021/10/12 23:01
 */
public class PeoplesNetwork implements Observer {
    public PeoplesNetwork(Observable observable) {
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("人民网:"+arg);
    }
}
package cn.shentianlan.studytest.designmode.observer.javaExample;

import java.util.Observable;
import java.util.Observer;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 新华网
 * @date 2021/10/12 22:34
 */
public class XinHuaNet implements Observer {

    public XinHuaNet(Observable observable) {
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("新华网:"+arg);
    }
}

测试 ObserverTest:

package cn.shentianlan.studytest.designmode.observer.javaExample;

/**
 * @author 渊蓝
 * @version 1.0
 * @description 使用Java内置观察者模式测试类
 * @date 2021/10/12 23:20
 */
public class ObserverTest {
    public static void main(String[] args) {
        Reporter reporter = new Reporter();
        PeoplesNetwork peoplesNetwork = new PeoplesNetwork(reporter);
        XinHuaNet xinHuaNet = new XinHuaNet(reporter);

        reporter.setNews("记者小蓝报道:最近天气不错");

        //移除人民网观察者
        reporter.deleteObserver(peoplesNetwork);

        reporter.setNews("记者小李报道:最近可能会下暴雨");
    }
}

结果:

新华网:记者小蓝报道:最近天气不错
人民网:记者小蓝报道:最近天气不错
新华网:记者小李报道:最近可能会下暴雨

4 Java内置的观察者对象存在的缺陷(Head First设计模式(中文版))

  • java.util.Observable 是一个类 而不是一个接口 ,这限制了它的使用和复用。这不符合设计原则(针对接口编程,而非针对实现编程)。
  • 由此会造成的问题:
    • 首先,因为Observable是一个“类”,导致我们必须设计一个类继承它。如果某类想同时具有Observable类和另一个超类的行为,就会陷入两难,毕竟Java不支持多重继承。这限制了Observable的复用潜力(而增加复用潜力不正是我们使用模式最原始的动机吗?)。
    • 再者,因为没有Observable接口,所以你无法建立自己的实现,和Java内置的Observer API搭配使用,也无法将java.util的实现换成另一套做法的实现(比方说,如果你能够扩展java.util.Observable,那么Observable“可能”可以符合你的需求。否则,你可能需要自己实现这一整套观察者模式。如果你看看Observable API,你会发现setChanged()方法被保护起来了(被定义成protected)。这意味着:除非你继承自Observable,否则你无法创建Observable实例并组合到你自己的对象中来。这个设计违反了第二个设计原则:“多用组合,少用继承”

5 JDK中使用观察者模式的案例

​ JavaBeans和Swing中,也都实现了观察者模式

​ 让我们看看一个简单的SwingAAPI:JButton。如果你观察一下JButton的超类AbstractButton,会看到许多增加与删除倾听者(listener)的方法,这些方法可以让观察者感应到Swing组件的不同类型事件。比方说:ActionListener让你“倾听”可能发生在按钮上的动作,例如按下按钮。你可以在Swing API中找到许多不同类型的倾听者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值