三种观察者设计模式实现

目录

1.观察者模式的组成

2.简单实现观察者模式

3.JDK实现观察者模式

4.使用Spring实现观察者模式


察者设计模式又被称作发布订阅模式,是定义对象之间一对多关系的一种设计模式。当一个对象A发生改变的时候,关注A的其他对象也会得到通知并发生改变。

观察者设计模式在项目中的使用是比较多的,例如一个经典的场景:用户注册成功之后,会发生赠送相应的积分(A),赠送优惠券(B),发送注册成功邮件(C)等动作。如果我们使用传统的调用,那么注册的这个接口,就要调用A,B,C三个接口。但是其实对于用户中心来说,是不关注积分赠送,优惠券赠送这类问题的。并且,如果以后产品又提了一个需求,用户注册成功之后,还得发送短信,生成一些其他的初始化信息,那我们是不是还得去改注册接口,这样的耦合性就太高了,也不容易扩展。

1.观察者模式的组成

观察者模式主要由四个部分组成:

  • Subject(抽象主题):又被称为“被观察者”,一般是接口或者抽象类,提供三个抽象方法:增加观察者,删除观察者,通知观察者
  • Observer(抽象观察者):又被称为“订阅者接口”,主要功能为提供一个更新的方法,当Subject发生变化的时候,能够更新自身的状态
  • Concrete Subject(具体主题):实现抽象主题中的方法
  • Concrete Observer(具体观察者):实现抽象观察者中的方法

类图可以表示如下(https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html):

2.简单实现观察者模式

下面以气象站的例子,写一个简单的观察者模式。当气象站发布了天气之后,需要进行统计和广播该天气变化。

package com.xiaohuihui.design.observer;

import java.util.List;

/**
 * @Desription: 主题接口
 * @Author: yangchenhui
 * @Date: 2019/11/26 14:17
 */
public interface Subject {

    /**
     * 添加观察者
     *
     * @param observer
     */
    void addObserver(Observer observer);

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

    /**
     * 通知观察者
     *
     * @param observerList
     */
    void notifyObservers(List<Observer> observerList);

}


package com.xiaohuihui.design.observer;

/**
 * @Desription: 订阅者接口
 * @Author: yangchenhui
 * @Date: 2019/11/26 14:19
 */
public interface Observer {

    /**
     * 更新状态
     *
     * @param temp
     * @param pressure
     */
    void update(float temp, float pressure);

}


package com.xiaohuihui.design.observer;

/**
 * @Desription: 展示接口
 * @Author: yangchenhui
 * @Date: 2019/11/26 14:23
 */
public interface Display {

    void display();

}


package com.xiaohuihui.design.observer;

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

/**
 * @Desription: 气象站
 * @Author: yangchenhui
 * @Date: 2019/11/26 14:25
 */
public class WheatherData implements Subject {

    /**
     * 订阅者集合
     */
    private List<Observer> observers;

    /**
     * 温度
     */
    private float temp;
    /**
     * 气压
     */
    private float pressure;

    public WheatherData() {
        observers = new ArrayList<>();
    }

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        if (observers != null && observers.contains(observer)) {
            observers.remove(observer);
        }
    }

    @Override
    public void notifyObservers(List<Observer> observerList) {
        if (observers != null && observers.size() > 0) {
            for (Observer observer : observers) {
                observer.update(temp, pressure);
            }
        }
    }

    /**
     * 更新天气数据
     *
     * @param temp
     * @param pressure
     */
    public void updateWheatherData(float temp, float pressure) {
        this.setTemp(temp);
        this.setPressure(pressure);
        this.notifyObservers(observers);
    }

    public List<Observer> getObservers() {
        return observers;
    }

    public void setObservers(List<Observer> observers) {
        this.observers = observers;
    }

    public float getTemp() {
        return temp;
    }

    public void setTemp(float temp) {
        this.temp = temp;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }
}


package com.xiaohuihui.design.observer;

/**
 * @Desription: 显示当前天气布告板
 * @Author: yangchenhui
 * @Date: 2019/11/26 14:44
 */
public class NowWeatherBroadcast implements Observer, Display {

    /**
     * 温度
     */
    private float temp;
    /**
     * 气压
     */
    private float pressure;
    /**
     * 订阅主题
     */
    private Subject subject;

    /**
     * 构造实例并注册到主题上
     *
     * @param subject
     */
    public NowWeatherBroadcast(Subject subject) {
        this.subject = subject;
        subject.addObserver(this);
    }

    @Override
    public void display() {
        System.out.println("====> 现在的天气数据  temp: " + temp + "  pressure: " + pressure);
    }

    @Override
    public void update(float temp, float pressure) {
        this.temp = temp;
        this.pressure = pressure;
        this.display();
    }

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }
}


package com.xiaohuihui.design.observer;

/**
 * @Desription: 统计天气布告板
 * @Author: yangchenhui
 * @Date: 2019/11/26 14:53
 */
public class StatisticsWeatherBroadcast implements Observer, Display {
    /**
     * 温度
     */
    private float temp;
    /**
     * 气压
     */
    private float pressure;
    /**
     * 订阅主题
     */
    private Subject subject;

    /**
     * 构造实例并注册到主题上
     *
     * @param subject
     */
    public StatisticsWeatherBroadcast(Subject subject) {
        this.subject = subject;
        subject.addObserver(this);
    }

    @Override
    public void display() {
        System.out.println("====> 开始统计天气数据  temp: " + temp + "  pressure: " + pressure);
    }

    @Override
    public void update(float temp, float pressure) {
        this.temp = temp;
        this.pressure = pressure;
        this.display();
    }

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }
}


package com.xiaohuihui.design.observer;

/**
 * @Desription:
 * @Author: yangchenhui
 * @Date: 2019/11/26 14:55
 */
public class ObserverTest {

    public static void main(String[] args) {
        WheatherData wheatherData = new WheatherData();
        NowWeatherBroadcast broadcast1 = new NowWeatherBroadcast(wheatherData);
        StatisticsWeatherBroadcast broadcast2 = new StatisticsWeatherBroadcast(wheatherData);
        wheatherData.updateWheatherData(123.1F, 1.00F);
    }

}

运行结果如下:

3.JDK实现观察者模式

除了自己实现观察者模式之外,JDK也给我们提供了相关的类。

可以通过继承Observable类成为具体的“被观察者”,实现Observer接口成为具体的“观察者”。

下面是代码示例:

package com.xiaohuihui.design.observer.java;

import java.util.Observable;

/**
 * @author: yangch
 * @date: 2019/11/26 22:36
 * @Description: 使用java提供的观察者模式, 继承Observable相当于实现之前的Subject接口
 */
public class WheatherData2 extends Observable {

    /**
     * 温度
     */
    private float temp;
    /**
     * 气压
     */
    private float pressure;

    /**
     * 更新天气数据
     *
     * @param temp
     * @param pressure
     */
    public void updateWheatherData(float temp, float pressure) {
        this.setTemp(temp);
        this.setPressure(pressure);
        setChanged();
        notifyObservers();
    }

    public float getTemp() {
        return temp;
    }

    public void setTemp(float temp) {
        this.temp = temp;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }


}


package com.xiaohuihui.design.observer.java;

import com.xiaohuihui.design.observer.Display;

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

/**
 * @author: yangch
 * @date: 2019/11/26 22:40
 * @Description:
 */
public class NowWeatherBroadcast2 implements Observer, Display {

    /**
     * 订阅主题
     */
    private Observable observable;
    /**
     * 温度
     */
    private float temp;
    /**
     * 气压
     */
    private float pressure;

    public NowWeatherBroadcast2(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void display() {
        System.out.println("====> 现在的天气数据  temp: " + temp + "  pressure: " + pressure);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WheatherData2) {
            WheatherData2 wheatherData = (WheatherData2) o;
            this.setPressure(wheatherData.getPressure());
            this.setTemp(wheatherData.getTemp());
            display();
        }
    }

    public Observable getObservable() {
        return observable;
    }

    public void setObservable(Observable observable) {
        this.observable = observable;
    }

    public float getTemp() {
        return temp;
    }

    public void setTemp(float temp) {
        this.temp = temp;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }
}


package com.xiaohuihui.design.observer.java;

import com.xiaohuihui.design.observer.Display;

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

/**
 * @author: yangch
 * @date: 2019/11/26 22:40
 * @Description: 实现Observer相当于将当前类标记为一个观察者类
 */
public class StatisticsWeatherBroadcast2 implements Observer, Display {

    /**
     * 订阅主题
     */
    private Observable observable;
    /**
     * 温度
     */
    private float temp;
    /**
     * 气压
     */
    private float pressure;

    public StatisticsWeatherBroadcast2(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void display() {
        System.out.println("====> 统计天气数据  temp: " + temp + "  pressure: " + pressure);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WheatherData2) {
            WheatherData2 wheatherData = (WheatherData2) o;
            this.setPressure(wheatherData.getPressure());
            this.setTemp(wheatherData.getTemp());
            display();
        }
    }

    public Observable getObservable() {
        return observable;
    }

    public void setObservable(Observable observable) {
        this.observable = observable;
    }

    public float getTemp() {
        return temp;
    }

    public void setTemp(float temp) {
        this.temp = temp;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }
}


package com.xiaohuihui.design.observer.java;

/**
 * @author: yangch
 * @date: 2019/11/26 22:48
 * @Description:
 */
public class JavaObserverTest {

    public static void main(String[] args) {

        WheatherData2 wheatherData = new WheatherData2();
        NowWeatherBroadcast2 nowWeatherBroadcast = new NowWeatherBroadcast2(wheatherData);
        StatisticsWeatherBroadcast2 statisticsWeatherBroadcast = new StatisticsWeatherBroadcast2(wheatherData);
        wheatherData.updateWheatherData(999.98F, 21.123F);

    }

}

测试结果如下:

4.使用Spring实现观察者模式

  • 通过继承ApplicationEvent成为“被观察者”
  • 通过实现ApplicationListener成为“观察者”
  • 通过实现ApplicationEventPublisherAware接口,获取到ApplicationEventPublisher对象,通过ApplicationEventPublisher发布事件

也可以直接使用@Resource或者@Autowired注解直接注入ApplicationEventPublisher对象。使用@EventListener来标识监听的方法。

下面是简单的代码示例:

package com.xiaohuihui.observer;

import org.springframework.context.ApplicationEvent;

/**
 * @Desription: 用户注册事件
 * @Author: yangchenhui
 * @Date: 2020/6/4 19:21
 */
public class UserRegisterEvent extends ApplicationEvent {

    public UserRegisterEvent(Object source) {
        super(source);
    }

}

package com.xiaohuihui.observer;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;

/**
 * @Desription: 用户注册
 * @Author: yangchenhui
 * @Date: 2020/6/4 19:24
 */
@Service
public class UserServiceImpl implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 用户注册
     *
     * @return
     */
    public Boolean userRegister(String userName) {
        System.out.println(userName + "用户注册成功");
        applicationEventPublisher.publishEvent(new UserRegisterEvent(userName));
        return true;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}


package com.xiaohuihui.observer;

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

/**
 * @Desription: 发送注册成功邮件
 * @Author: yangchenhui
 * @Date: 2020/6/4 19:29
 */
@Service
public class EmailServiceImpl implements ApplicationListener<UserRegisterEvent> {

    @Override
    public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
        System.out.println(userRegisterEvent.getSource() + "注册成功,发送注册邮件");
    }

}


package com.xiaohuihui.observer;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

/**
 * @Desription: 赠送积分
 * @Author: yangchenhui
 * @Date: 2020/6/4 19:44
 */
@Service
public class SocreServiceImpl {

    @EventListener
    public Boolean presentScore(UserRegisterEvent userRegisterEvent){
        System.out.println(userRegisterEvent.getSource() + "注册成功,赠送1000积分");
        return true;
    }

}


package com.xiaohuihui.observer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

/**
 * @Desription: 注解方式使用Spring事件发布订阅
 * @Author: yangchenhui
 * @Date: 2020/6/4 19:41
 */
@Service
public class UserServiceImpl2 {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 用户注册
     *
     * @return
     */
    public Boolean userRegister(String userName) {
        System.out.println(userName + "用户注册成功");
        applicationEventPublisher.publishEvent(new UserRegisterEvent(userName));
        return true;
    }

}


package com.xiaohuihui.observer;

import com.xiaohuihui.XiaohuihuiSpringbootApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Desription:
 * @Author: yangchenhui
 * @Date: 2020/6/4 19:52
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = XiaohuihuiSpringbootApplication.class)
public class UserServiceImplTest {

    @Autowired
    private UserServiceImpl userServiceImpl;
    @Autowired
    private UserServiceImpl2 userServiceImpl2;

    @Test
    public void userRegister() {

        userServiceImpl.userRegister("xiaohuihui111");
        userServiceImpl2.userRegister("xiaohuihui222");

    }
    
}

运行结果如下:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值