[设计模式Java实现附plantuml源码~行为型]对象间的联动~观察者模式

前言:

为什么之前写过Golang 版的设计模式,还在重新写Java 版?

答:因为对于我而言,当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言,更适合用于学习设计模式。

为什么类图要附上uml

因为很多人学习有做笔记的习惯,如果单纯的只是放一张图片,那么学习者也只能复制一张图片,可复用性较低,附上uml,方便有新理解时,快速出新图。


🔥[设计模式Java实现附plantuml源码]专链

  • 创建型
  1. 确保对象的唯一性~单例模式
  2. 集中式工厂的实现~简单工厂模式
  3. 多态工厂的实现------工厂方法模式
  4. 产品族的创建------抽象工厂模式
  5. 对象的克隆~原型模式
  6. 复杂对象的组装与创建------建造者模式
  • 结构型
  1. 提供统一入口------外观模式
  2. 扩展系统功能------装饰模式
  3. 树形结构的处理------组合模式
  4. 对象的间接访问------代理模式
  5. 不兼容结构的协调------适配器模式
  6. 处理多维度变化------桥接模式
  7. 实现对象的复用------享元模式
  • 行为型
  1. 请求的链式处理------职责链模式

  2. 请求发送者与接收者解耦------命令模式

  3. 遍历聚合对象中的元素------迭代器模式

  4. 协调多个对象之间的交互------中介者模式

  5. 对象间的联动~观察者模式


文章目录


对象间的联动~观察者模式

观察者模式是使用频率最高的设计模式之一,用于建立对象与对象之间的依赖关系。

一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者。一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

观察者模式定义如下:

观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。

观察者模式结构中通常包括观察目标和观察者两个继承层次结构,其结构如图所示。

uml 复制代码
@startuml

abstract class Subject {
+ attach(Observer observer)
+ detach(Observer observer)
+ notify()
}

note left of Subject::notify
for(Observer obs: observers) {
   obs.update();
}
end note

abstract class Observer {
+ update()
}

class ConcreteSubject extends Subject {
- subjectState
+ gettersetter()
}

class ConcreteObserver extends Observer {
- observerState
+ update()
}

note right of ConcreteObserver::update
observerState = subject.getState();
end note
Subject -right-> Observer: observers
ConcreteObserver -left-> ConcreteSubject: subject


@enduml

由可以看出,在观察者模式结构图中包含以下4个角色。

(1)Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时定义了通知方法 notify()。目标类可以是接口,也可以是抽象类或具体类。

(2)ConcreteSubject(具体目标):具体目标是目标类的子类,通常包含有经常发生改变的数据。当它的状态发生改变时,向其各个观察者发出通知。同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有)。如果无须扩展目标类,则具体目标类可以省略。

(3)Observer(观察者):观察者将对观察目标的改变做出反应。观察者一般定义为接口,该接口声明了更新数据的方法 update(),因此又称为抽象观察者。

(4)ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致。它实现了在抽象观察者Observer中声明的 update() 方法。通常在实现时,可以调用具体目标类的 attach() 方法将自己添加到目标类的集合中或通过 detach() 方法将自己从目标类的集合中删除。

观察者模式描述了如何建立对象与对象之间的依赖关系,以及如何构造满足这种需求的系统。

观察者模式包含观察目标和观察者两类对象。一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,所有的观察者都将得到通知。作为对这个通知的响应,每个观察者都将监视观察目标的状态以使其状态与目标状态同步,这种交互也称为发布-订阅(Publish-Subscribe)。观察目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅它并接收通知。

简单代码实现

java 复制代码
package behavior;


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


// Client code
public class ObserverDemo {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        new ConcreteObserverA(subject,1);
        ConcreteObserverB observerB = new ConcreteObserverB(subject,2);

        subject.setState("Initial State");
        subject.myNotify();

        subject.setState("Updated State");
        subject.myNotify();
        subject.detach(observerB);
        subject.setState("final State");
        subject.myNotify();
    }


    // 目标类
    public abstract static class Subject {
        protected HashMap<Integer, Observer> observers = new HashMap<>();

        public void attach(Observer observer) {
            observers.put(observer.id, observer);
        }

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

        public void myNotify() {
            observers.forEach((id, observer) -> observer.update() );
        }

        public abstract String getState();

        public abstract void setState(String state);
    }

    // Observer abstract class
    public abstract static class Observer {
        protected Integer id;
        protected String observerState;
        protected Subject subject;

        protected String prevState;
        // getter setter
        public abstract void update();

    }

    // ConcreteSubject class
    public static class ConcreteSubject extends Subject {
        private String subjectState;

        @Override
        public String getState() {
            return subjectState;
        }

        @Override
        public void setState(String state) {
            this.subjectState = state;
        }
    }

    // ConcreteObserver class
    public static class ConcreteObserverA extends Observer {

        public ConcreteObserverA(Subject subject, Integer id) {
            this.subject = subject;
            this.id = id;
            this.subject.attach(this);
        }

        @Override
        public void update() {
            prevState =  observerState;
            observerState = subject.getState();
            System.out.println(">>>>a prev state="+prevState + " new state="+observerState);
        }
    }

    public static class ConcreteObserverB extends Observer {

        public ConcreteObserverB(Subject subject, Integer id) {
            this.subject = subject;
            this.id = id;
            this.subject.attach(this);
        }

        @Override
        public void update() {
            prevState = observerState;
            observerState = subject.getState();
            System.out.println(">>>>b prev state="+prevState + " new state="+observerState);
        }
    }
}

结果输出

shell 复制代码
>>>>a prev state=null new state=Initial State
>>>>b prev state=null new state=Initial State
>>>>a prev state=Initial State new state=Updated State
>>>>b prev state=Initial State new state=Updated State
>>>>a prev state=Updated State new state=final State

简单总结

观察者模式是一种使用频率非常高的设计模式,无论是移动应用、Web应用或者桌面应用,观察者模式几乎无处不在。它为实现对象之间的联动提供了一套完整的解决方案,凡是涉及一对一或者一对多的对象交互场景都可以使用观察者模式。观察者模式广泛应用于各种编程语言的GUI事件处理的实现,在基于事件的XML解析技术(例如SAX2)以及Web事件处理中也都使用了观察者模式。

主要优点

观察者模式的主要优点如下:

(1)观察者模式可以实现表示层和数据逻辑层的分离。它定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。

(2)观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。

(3)观察者模式支持广播通信。观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。

(4)观察者模式满足开闭原则的要求,增加新的具体观察者无须修改原有系统代码。在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。

主要缺点

观察者模式的主要缺点如下:

(1)如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。

(2)如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

(3)观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

适用场景

在以下情况下可以考虑使用观察者模式:

(1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用。

(2)一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁。

(3)需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象......可以使用观察者模式创建一种链式触发机制。



🚀 作者简介:作为某云服务提供商的后端开发人员,我将在这里与大家简要分享一些实用的开发小技巧。在我的职业生涯中积累了丰富的经验,希望能通过这个博客与大家交流、学习和成长。技术栈:Java、Golang、PHP、Python、Vue、React


本文收录于三木的

💐 「设计模式」专栏

此外三木还有以下专栏在同步更新~

🌼 「AI」专栏

🔥「面试」这个专栏的灵感来自于许多粉丝私信,大家向我咨询有关面试的问题和建议。我深感荣幸和责任,希望通过这个专栏,能够为大家提供更多关于面试的知识、技巧和经验。我们将一起探讨面试。期待粉丝们ssp的offer喜讯。

🎈 「Java探索者之路」系列专栏,这个专栏旨在引领Java开发者踏上一段真正探索Java世界的旅程。

我们将深入探讨Java编程的方方面面,从基础知识到高级技巧,从实践案例到最新趋势,帮助你成为一名卓越的Java探索者。如果有想进入Java后端领域工作的同学,这个专栏会对你有所帮助,欢迎关注起来呀

🌊 「Python爬虫」的入门学习系列,大家有兴趣的可以看一看


🌹一起学习,互三互访,顺评论区有访必回,有关必回!!!


相关推荐
我焦虑的编程日记3 分钟前
【RabbitMQ】RabbitMQ学习
java·数据库·java-ee
晚睡早起₍˄·͈༝·͈˄*₎◞ ̑̑14 分钟前
JavaWeb(二)
java·数据仓库·hive·hadoop·maven
CoderJia程序员甲1 小时前
重学SpringBoot3-集成Redis(一)
java·redis·缓存·springboot
speop1 小时前
408笔记|随笔记录|自用|2
java·redis·笔记
王维诗里的代码i2 小时前
Redis基础二(spring整合redis)
java·数据库·redis·spring
J不A秃V头A2 小时前
iTextPDF中,要实现表格中的内容在数据长度超过边框时自动换行
java·pdf
椰椰椰耶3 小时前
【Spring】@RequestMapping、@RestController和Postman
java·后端·spring·mvc
CocoaAndYy3 小时前
Java实现限流算法(四种)
java·开发语言·算法
所待.3833 小时前
设计循环队列
java·开发语言·数据结构
脑瓜疼啊脑瓜疼3 小时前
Java中的自定义异常
java·开发语言