设计模式之观察者模式

本文介绍了观察者模式,一种用于处理对象一对多关系的设计模式。通过一个温度系统的实例,展示了在没有使用观察者模式时遇到的问题,以及采用观察者模式后如何优雅地解决这些问题。文章详细阐述了观察者模式的角色,包括观察者和主题,并提供了相应的接口定义和代码实现,说明了如何注册、移除观察者以及在主题状态改变时通知所有观察者。
摘要由CSDN通过智能技术生成

观察者模式

当对象之间存在一对多的关系时,可以使用观察者模式。

事例引入

现在有一个温度系统,这个系统有许多的用户,当温度改变时,该系统便会通知所有的用户,更新用户的温度信息。

温度系统

若不使用观察者模式,这样的一个系统该如何实现呢?如下:

public class TemperatureSystem {
    User userA;
    User userB;
    User userC;
    
    public void temperatureChange(double temperature){
        userA.setTemperature(temperature);
        userB.setTemperature(temperature);
        userC.setTemperature(temperature);
    }
}

温度系统直接拥有这三个用户,当温度被改变时,调用temperatureChange方法,将三个用户的温度信息直接改变。

这个系统看上去没有问题,但是现在有了新需求:由于这个系统太好用了!(真的吗?),有个用户D也想加入进来,它也想在温度变化时被通知,那上述的代码该如何维护呢?它需要修改原来的代码!再和userD强耦合,然后在temperatureChange方法里添加进userD,这不仅麻烦,还违反了开闭原则:对修改关闭,对拓展开放

同理,如果用户B觉得这套系统不好用,想退出,那也不得不修改原先的代码…

由上述的需求例子,我们对这套系统有了这样的需求:

  • 当有用户加入该系统时,不需要修改代码
  • 当有用户退出该系统时,不需要修改代码
  • 当温度变化时,需要通知所有的用户

观察者模式的角色

  • 观察者:需要收到信息的角色,对应上述例子中的用户
  • 主题:通知观察者们信息的角色,对应上述例子中的温度系统

观察者模式的代码实现

主题接口 Subject

该接口主要有三个方法:

  • registerObserver():将一个用户注册成为观察者
  • removeObserver():将一个观察者从主题中移除
  • notifyObserver():通知所有的观察者,并给它们传输新的数据
public interface Subject {
    void registerObserver();
    void removeObserver();
    void notifyObserver();
}

观察者接口 Observer

观察者接口仅需要持有update方法即可

public interface Observer {
    void update(double temperature);
}

主题类 TemperatureSystem

主题类需要实现主题接口,并且实现接口的三个方法

主题类持有一个list来存储所有的观察者,当有观察者注册时,将其添加到list中,反之亦然

而当主题类更新它的属性temperature时,需要通知所有的观察者,并将数据传输给所有的观察者,即调用观察者的update方法

public class TemperatureSystem implements Subject{
    private ArrayList<Observer> list;
    private double temperature;

    public TemperatureSystem() {
        list = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        list.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        list.remove(observer);
    }

    @Override
    public void notifyObserver() {
        for (Observer observer : list) {
            observer.update(temperature);
        }
    }

    public void setTemperature(double temperature) {
        this.temperature = temperature;
        notifyObserver();
    }
}

观察者类 User

观察者类需要持有一个主题对象,以方便注册和移除(当然也可以不持有)

当用户初始化时,便可以将自己注册成为一个观察者,当然也可以手动注册成为观察者,要看具体需求了

public class User implements Observer{
    private String name;
    private double temperature;
    private Subject subject;

    public User(String name, Subject subject) {
        this.name = name;
        this.subject = subject;
        subject.registerObserver(this);
    }

    @Override
    public void update(double temperature) {
        this.temperature=temperature;
        display();
    }

    public void removeObserver(){
        subject.removeObserver(this);
    }

    private void display(){
        System.out.println(name + "收到温度" + temperature);
    }
}

测试类 Main

public class Main {
    public static void main(String[] args) {
        TemperatureSystem subject = new TemperatureSystem();
        User userA = new User("用户A",subject);
        User userB = new User("用户B",subject);
        User userC = new User("用户C",subject);

        subject.setTemperature(52);
        userB.removeObserver();
        subject.setTemperature(13.14);
    }
}
输出
用户A收到温度100.0
用户B收到温度100.0
用户C收到温度100.0
用户A收到温度13.14
用户C收到温度13.14

总结

  • 如果需要注册新的用户成为观察者时,并不需要修改原来的代码,仅需要将其注册即可
  • 若用户不想成为观察者时,也仅需要将其移除即可
  • 同时在主题状态改变时,会通知所有的观察者以发送消息
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值