设计模式十九之观察者模式

观察者模式是一种设计模式,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。该模式降低了耦合,但也可能导致耦合和效率问题。在Java中,可以使用`java.util.Observable`和`Observer`接口,或是Google Guava的`EventBus`配合`@Subscribe`注解来实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心;股票价格与股民、微信公众号与微信用户、气象局的天气预报与听众、小偷与警察等。

1. 模式的定义与特点

1.1 模式的定义

  观察者模式(Observer):多个对象间存在一对多的关系,当一个对象的关系发生改变时,所有依赖它的对象都会得到通知并自动更新,这种模式有时又被成为发布-订阅模式。

1.2 模式的特点

  观察者模式的优点有:
    1. 降低了观察者与目标对象之间的耦合关系,两者之间是抽象耦合关系;
    2. 目标与观察者之间建立了一套触发机制。

  观察者模式的缺点有:
    1. 目标与观察者之间的耦合关系并没有彻底解除,而且有可能出现循环引用;
    2. 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

1.3 模式的使用场景

  1. 关联行为场景,建立一套触发机制。

2. 模式的结构与实现

2.1 模式的结构

  观察者模式的主要角色如下:
    1. 抽象主题角色(Subject):抽象目标类,提供了一个用户保存观察者对象的集合以及添加、删除观察者对象的方法,以及通知所有观察者的抽象方法;
    2. 具体主题角色(Concrete Subject):具体目标类,实现了抽象目标类中通知所有观察者的方法;
    3. 抽象观察者(Observer):它是一个抽象类或接口,包含了一个抽象的更新之间的方法,当接收到具体主题变更通知时调用;
    4. 具体观察者(Concrete Observer):实现了抽象观察者定义的抽象方法。

观察者模式类UML

2.2 模式的实现

抽象目标

/**
 * 抽象目标 - 上课铃响了
 */
public interface Event {

    void addListener(EventListener listener);

    void removeListener(EventListener listener);

    void notifyListeners();

}

具体目标

/**
 * 具体目标 - 上课铃响了
 */
public class RingEvent implements Event {

    private List<EventListener> listeners = new ArrayList<>();;

    @Override
    public void addListener(EventListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(EventListener listener) {
        listeners.remove(listener);
    }

    @Override
    public void notifyListeners() {
        System.out.println("上课铃响了...");
        listeners.forEach(listener -> listener.response());
    }
}

抽象观察者

/**
 * 抽象观察者
 */
public interface EventListener {

    void response();

}

具体观察者

/**
 * 具体观察者 - 老师
 */
public class TeacherEventListener implements EventListener {
    @Override
    public void response() {
        System.out.println("上课铃响了,老师走进了教师,开始上课...");
    }
}

/**
 * 具体观察者 - 学生
 */
public class StudentEventListener implements EventListener {

    @Override
    public void response() {
        System.out.println("上课铃响了,学生们走进了教室,开始上课...");
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        Event event = new RingEvent();
        TeacherEventListener teacherEventListener = new TeacherEventListener();
        StudentEventListener studentEventListener = new StudentEventListener();
        event.addListener(teacherEventListener);
        event.addListener(studentEventListener);
        event.notifyListeners();
    }
}

# 运行结果如下:
上课铃响了...
上课铃响了,老师走进了教师,开始上课...
上课铃响了,学生们走进了教室,开始上课...

3. 模式扩展

3.1 java.util.Observable 类与 Observer 接口 类

/**
 * 被观察者
 */
public class ringEvent extends Observable {

    public void ring() {
        System.out.println("上课铃响了...");
        setChanged();
        notifyObservers();
    }
}

/**
 * 观察者 - 老师
 */
public class TeacherListener implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("上课铃响了,老师走进了教室,开始上课...");
    }
}

/**
 * 观察者 - 学生
 */
public class StudentListener implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("上课铃响了,学生们走进了教室,开始上课了...");
    }
}

public class Client {

    public static void main(String[] args) {
        ringEvent ringEvent = new ringEvent();
        ringEvent.addObserver(new TeacherListener());
        ringEvent.addObserver(new StudentListener());
        ringEvent.ring();
    }

}

# 运行结果如下:
上课铃响了...
上课铃响了,学生们走进了教室,开始上课了...
上课铃响了,老师走进了教室,开始上课...

3.2 com.google.common.*.EventBus 和 @subscribe

/**
 * 观察者 - 订阅者
 */
public class TeacherListener {

    @Subscribe
    public void subScribe(String message) {
        System.out.println(message);
        System.out.println("上课铃响了,老师走进了教室,开始上课...");
    }

}

/**
 * 观察者 - 订阅者
 */
public class StudentListener {

    @Subscribe
    public void subScribe(String message) {
        System.out.println(message);
        System.out.println("上课铃响了,学生们走进了教室,开始上课了...");
    }

}

public class Client {

    public static void main(String[] args) {
        EventBus eventBus = new EventBus();
        eventBus.register(new TeacherListener());
        eventBus.register(new StudentListener());
        eventBus.post("上课铃响了...");
    }

}

# 运行结果如下:
上课铃响了...
上课铃响了,老师走进了教室,开始上课...
上课铃响了...
上课铃响了,学生们走进了教室,开始上课了...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值