设计模式之观察者模式

设计模式之观察者模式,第1张

文章目录
  • 前言
  • 一、认识观察者模式
  • 二、实现观察者模式
    • 实现过程
    • 实际应用情况描述
  • 总结
  • 参考资料

前言

本篇博客是关于观察者模式的实现,若文章中出现相关问题,请指出!

对应代码地址:Gitee(demo-exer/ java-Lear23designpatterns)、Github(java-demo/ java-Lear23designpatterns)

所有博客文件目录索引:博客目录索引(持续更新)

一、认识观察者模式

观察者模式定义:属于对象行为模式,当多个对象之间存在一对多的依赖关系,即一个对象的状态发生改变时,所以依赖它的对象都会得到通知并被自动更新。这种模式有时又被称为发布-订阅模式、模型-视图模式。

结构:

  1. 抽象主题角色(Subject):即抽象类,提供了添加、移除观察者的方法,以及一个通知所有观察者的抽象方法。
  2. 具体主题角色(Concrete Subject):也称为具体目标类,实现抽象目标中的通知方法,一旦该类内部发生了什么改变时,通知所有注册过的观察者对象。
  3. 抽象观察者(Observer):是一个抽象类或接口,包含了一个更新自己的抽象方法,当接到具体主题的更改时被调用。
  4. 具体观察者(Concrete Observer):实现抽象观察者中的更新方法,一旦目标角色发出更新通知时会调用该更新方法来更新自身的状态。

优缺点:

  • 优点:降低了目标与观察者之间的耦合关系,符合依赖倒置原则开闭原则。目标与观察者之间建立了一套触发机制。
  • 缺点:目标与观察者之间依赖关系并没有完全解除,可能出现循环引用。并且若是当在主题角色中的观察者过多时,通知发布会花费很多时间,影响程序的效率。

实际应用场景:

  1. JDK中的java.util.Observable
  2. Spring中的org.springframework.context.ApplicationListener


二、实现观察者模式 实现过程

demo见xyz.changlu.observer包下代码:

抽象观察者(接口):Observer

public interface Observer {
    void response();
}

抽象主题类:Subject

public abstract class Subject {
    protected List<Observer> observers = new ArrayList<>();

    //添加观察者到集合中
    public void addObserver(Observer observer){
        observers.add(observer);
    }

    //移除指定观察者
    public void removeObserver(Observer observer){
        observers.remove(observer);
    }

    //具体通知方法让实现类去实现
    public abstract void notifyAllObserver();
}

具体观察者:Task1Task2

//具体观察者1号
public class Task1 implements Observer {
    @Override
    public void response() {
        System.out.println("Task1收到通知,正在执行任务2.....");
    }
}

//具体观察者2号
public class Task2 implements Observer {
    @Override
    public void response() {
        System.out.println("Task2收到通知,正在执行任务2.....");
    }
}

具体主题者:ConcreteSubject

public class ConcreteSubject extends Subject {
    @Override
    public void notifyAllObserver() {
        System.out.println("收到通知");
        //开始通知到所有的观察者
        for (Observer observer : observers) {
            observer.response();
        }
    }
}

测试程序:测试类Customer

public class Customer {
    public static void main(String[] args) {
        //创建两个任务
        Task1 task1 = new Task1();
        Task2 task2 = new Task2();
        //创建主题角色,并添加两个观察者(及任务)
        ConcreteSubject subject = new ConcreteSubject();
        subject.addObserver(task1);
        subject.addObserver(task2);

        //进行更新通知
        subject.notifyAllObserver();
    }
}

  • 首先将多个任务(即观察者)添加到主题类中(存放在一个list集合里),一旦ConcreteSubject主题类进行了更新 *** 作,即可调用其实现Subject抽象类的实现方法notifyAllObserver()来通知观察者集合中的各个观察者执行任务。

说明:解决的是当一个对象进行更新或其他 *** 作时对应要去更改执行或通知多个任务时,我们即可以使用观察者模式。



实际应用情况描述

问题描述

若是主题进行了更新,并且该更新涉及到了需要个部分,此时你会怎么呢?若是没有了解过观察者模式的也许会这样:

class Weather{
    
    //执行更新 *** 作
    public void update(){
        dao.update();//本方法核心的更新 *** 作
        //通知的 *** 作
        Task task = new Task();
        Task2 task2 = new Task2();
        task.doThing1();
        task2.doThing2();
    }
}

class Task{
    void doThing1(){
        ...
    }
}

class Task2{
    void doThing2(){
        ....
    }
}

你可能会在update() *** 作中去new多个对象并且逐一执行,若是某一天要少通知一个单位的话还需要去手动删除…


解决对策

创建一个抽象类,其包含了一个集合专门用来存放多个观察者对象,并包含添加、移除 *** 作:

//抽象主题
public abstract class Subject {
    protected List<Observer> observers = new ArrayList<>();

    //添加观察者到集合中
    public void addObserver(Observer observer){
        observers.add(observer);
    }

    //移除指定观察者
    public void removeObserver(Observer observer){
        observers.remove(observer);
    }

    public abstract void notifyAllObserver();
}

再创建一个抽象观察者接口,其带有一个通知方法:

public interface Observer {
    void response();
}

万事具备了,我们开始改造原来的两个类:

class Weather extends Subject{
    
    //执行更新 *** 作
    public void update(){
        dao.update();//本方法核心的更新 *** 作
        //调用通知 *** 作即可!!!
        notifyAllObserver();
    }
    
    //实现一个通知方法
    @Override
    public void notifyAllObserver() {
        //通知所有的观察者开始执行其自己的 *** 作
        for (Observer observer : observers) {
            observer.response();
        }
    }
}

//两个任务分别实现了观察者接口
class Task implements Observer{
    void doThing1(){
        ...
    }
    
    @Override
    public void response() {
        doThing1();//不仅仅可以添加该方法,还可以添加其他方法
    }
}

class Task2{
    void doThing2(){
        ....
    }
    
    @Override
    public void response() {
        doThing2();//不仅仅可以添加该方法,还可以添加其他方法
    }
}

测试使用时:

public class Customer {
    public static void main(String[] args) {
        Weather weather = new Weather();
        //添加指定的任务
        weather.addObserver(new Task());
        weather.addObserver(new Task2());
        //执行其中的更新 *** 作
        weather.update();//此时调用更新 *** 作时,自动会执行集合中的所有观察者 *** 作
    }
}

感悟:在对观察者模式进行思考时,将模式应用到实际案例中去,去通过使用设计模式来去解决整个项目的架构问题,提高方法解耦!!!



总结

1、对于观察者模式,在出现一对多的关系 *** 作时可以进行使用来实现方法解耦,一般应当是当要执行更新或其他 *** 作影响到很多个对象时,为了方便管理通知可以使用到该模式。

2、优点是符合开闭原则、依赖倒置原则,对于目标与观察者之间建立了连接。缺点是依赖关系没有完全解除,若是观察者过多通知发布会耗费很多时间,影响程序的效率。



参考资料

视频:2020年最详细的23种Java设计模式完整视频教程全集 观察者模式

[1]. 观察者模式(Observer模式)详解

[2]. 设计模式之观察者模式 包含一个天气的例子

我是长路,感谢你的耐心阅读。如有问题请指出,我会积极采纳!
欢迎关注我的公众号【长路Java】,分享Java学习文章及相关资料
Q群:851968786 我们可以一起探讨学习
注明:转载可,需要附带上文章链接

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/794445.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存