Java设计模式之行为型-观察者模式(UML类图+案例分析)

目录

一、基本概念

二、UML类图

三、角色设计

四、代码实现

案例一

案例二

案例三

五、总结


一、基本概念

观察者先订阅被观察者对象,当被观察者的状态发生变化时,观察者可以及时收到消息,在这种模式当中,被观察者维护了一个观察者列表,并提供了添加、删除、通知观察者的方法。

二、UML类图

Java设计模式之行为型-观察者模式(UML类图+案例分析)_第1张图片

三、角色设计

角色 描述
抽象主题 抽象被观察者,提供注册和移除观察者、通知观察者的接口
具体主题 将有关状态存入具体观察者对象,当自己的状态发生改变时,给所有登记过的观察者发出通知
抽象观察者 定义了一个更新接口,使得在得到主题更改通知时更新自己
具体观察者 实现抽象观察者接口,以便在得到主题的通知时更新自身的状态

四、代码实现

这边我分享了三个案例,分别是通过自定义撰写、JDK源码封装和Spring框架封装三种去实现。

案例一

假设有一个被观察者:CSDN博主,它有2个粉丝分别是Jack和Tom,当CSDN发布了通知,对应的粉丝都会收到私信。

定义被观察者接口:

public interface Blogger {

    /**
     * 新增粉丝
     */
    void addFans(Fans fans);

    /**
     * 移除粉丝
     */
    void removeFans(Fans fans);

    /**
     * 通知粉丝
     */
    void sendMessage(String message);
}

被观察者具体实现类:

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

public class CSDN implements Blogger {

    private List fansList = new ArrayList<>();


    @Override
    public void addFans(Fans fans) {
        this.fansList.add(fans);
    }

    @Override
    public void removeFans(Fans fans) {
        this.fansList.remove(fans);
    }

    @Override
    public void sendMessage(String message) {
        for(Fans fans : fansList){
            fans.receiveMessage(message);
        }
    }
}

定义观察者接口:

public interface Fans {

    void receiveMessage(String message);

}

定义具体观察者实现类:

public class JackFans implements Fans {
    @Override
    public void receiveMessage(String message) {
        System.out.println("Jack收到了私信:"+message);
    }
}

public class TomFans implements Fans {

    @Override
    public void receiveMessage(String message) {
        System.out.println("Tom收到了私信:"+message);
    }
}

客户端:

public class Client{

    public static void main(String[] args) {
        Blogger blogger = new CSDN();
        Fans jackFans = new JackFans();
        Fans tomFans = new TomFans();
        blogger.addFans(jackFans);
        blogger.addFans(tomFans);
        blogger.sendMessage("CSDN发布了《关于社区整顿的通知》");
        blogger.removeFans(jackFans);
        blogger.sendMessage("CSDN发布了《关于博客发布调整的通知》");

    }
}

运行结果如下:

Java设计模式之行为型-观察者模式(UML类图+案例分析)_第2张图片

案例二

这个案例依旧是实现上述逻辑,只不过我们使用JDK提供的接口去实现,过程如下。

定义被观察者具体实现类:

import java.util.Observable;

public class CSDN extends Observable {

    @Override
    public void notifyObservers(Object arg) {
        //修改状态为可以群发
        setChanged();
        //调用父类的notifyObservers 群发消息
        super.notifyObservers(arg);
    }
}

定义观察者具体实现类:

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

public class TomFans implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Tom收到了私信:"+arg);
    }
}

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

public class JackFans implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Jack收到了私信:"+arg);
    }
}

客户端:

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

public class Client{

    public static void main(String[] args) {
        Observable csdn = new CSDN();
        Observer tomFans = new TomFans();
        Observer jackFans = new JackFans();
        csdn.addObserver(tomFans);
        csdn.addObserver(jackFans);
        csdn.notifyObservers("《关于整顿社区的通知》");
        csdn.deleteObserver(tomFans);
        csdn.notifyObservers("《关于更新CSDN社区的通知》");
    }
}

运行结果如下:

Java设计模式之行为型-观察者模式(UML类图+案例分析)_第3张图片

有了JDK提供的接口去实现,整体代码结构更简洁和方便了! 

案例三

这个案例依旧是上述逻辑,只不过我们这边使用Spring提供的封装事件的监听去实现,这边省去了搭建Spring框架的流程,直接看核心代码就行!

ApplicationEvent和Listener实际上就是Spring基于观察者模式设计的发布-订阅事件模型。

ApplicationEvent :自定义的事件对象,用于表示具体的事件。

具体代码如下:

import org.springframework.context.ApplicationEvent;

public class CSDN extends ApplicationEvent {

    private String message;

    public CSDN(Object source,String message) {
        super(source);
        this.message = message;
    }

    public String getMessage(){
        return this.message;
    }

    public void setMessage(String message){
        this.message = message;
    }

}

ApplicationListener:事件监听器接口,用于监听特定事件:

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class JackFans implements ApplicationListener {
    @Override
    public void onApplicationEvent(CSDN event) {
        System.out.println("Jack收到私信:"+event.getMessage());
    }
}


import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class TomFans implements ApplicationListener {
    @Override
    public void onApplicationEvent(CSDN event) {
        System.out.println("Tom收到私信:"+event.getMessage());
    }
}

单元测试:

ApplicationContext:Spring上下文,用于广播ApplicationEvent,并通知相关的ApplicationListener。

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;

@SpringBootTest
class ObserverApplicationTests {

    @Resource
    private ApplicationContext applicationContext;

    @Test
    void contextLoads() {
        CSDN csdn = new CSDN(this,"发布了《关于整顿社区的通知》");
        applicationContext.publishEvent(csdn);
    }

}

运行结果如下:

Java设计模式之行为型-观察者模式(UML类图+案例分析)_第4张图片

通过这种方式,不同的业务逻辑模块就可以不依赖于具体的实现,只通过监听特定事件来响应,从而实现解耦。

事件驱动的编程方式还有以下优点:

1、降低耦合度

2、提高模块间的独立性和可重用性

3、易于扩展和维护

总的来说,ApplicationEvent和Listener的设计初衷就是为了解耦和提高系统的扩展性、稳定性。 

五、总结

优点:

1观察者和被观察者解耦,增强了灵活性。

2符合开闭原则,容易扩展。

3支持广播通信,一个对象状态变化会通知多个观察者对象。

4建立一套触发机制。

缺点:

1如果观察者很多,通知的开销很大。

2被观察者发送通知,无法知道有哪些观察者处理。

应用场景:

1需要一对多依赖关系的场景,一个对象状态变化需要通知其他多个对象。

2跨系统的消息交换,如消息队列的生产者和消费者。

3事件驱动型程序,如按钮点击触发的响应。

符合的设计原则:

1、单一职责原则(Single Responsibility Principle)

观察者和被观察者职责明确区分,都仅负责自己的功能。

2、开闭原则(Open Closed Principle)

可以新增观察者而不影响被观察者,扩展开放。

3、里氏替换原则(Liskov Substitution Principle)

观察者都遵循统一接口,扩展观察者不会对系统造成影响。

4、依赖倒转原则(Dependency Inversion Principle)

被观察者和观察者都依赖于抽象接口,不依赖具体实现。

5、接口隔离原则(Interface Segregation Principle)

观察者接口只定义了更新接口,避免了冗余。

综上,观察者模式建立一套触发机制和依赖关系,用于被观察对象状态变化时自动通知观察者,是一对多通信的最佳设计模式。

你可能感兴趣的:(Java,设计模式,Spring,设计模式,观察者模式)