Java设计模式(十八)行为型- 观察者模式Observer Mode(史上最全职责链模式)与使用场景以及优缺点

1.观察者模式Observer Mode

观察者模式,又叫发布-订阅(Publish/Subscribe)模式,模型-视图(Model/View)模式,源-监听器(Source/Listener)模式或从属者(Dependents)模式。定义一种一对多的依赖关系,一个主题对象可被多个观察者同时监听,使得每当主题对象状态变化时,所有依赖于它的对象都会得到通知并被自动更新。

1.1 代码实现

通过一个微信用户(观察者)订阅公众号(被观察者)接收公众号推送消息的例子来进行简单的代码实现:

// 抽象观察者接口
public interface Observer {
    void update(String message);
}
// 微信用户类 具体的观察者
@AllArgsConstructor
public class WeixinUser implements Observer {
    private String name;
    @Override
    public void update(String message) {
        System.out.println(name + "接收到了消息(观察到了):" + message);
    }
}
// 被观察者接口
public interface Observable {
    // 新增用户(新增观察者)
    void add(Observer observer);
    // 移除用户,或者说用户取消订阅(移除观察者)
    void del(Observer observer);
    // 发布 推送消息
    void notify(String message);
}
// 具体的被观察者(公众号)
public class Subject implements Observable {
    // 观察者列表(订阅用户)
    private List<Observer> list = new ArrayList<>();
    @Override
    public void add(Observer observer) {
        list.add(observer);
    }
    @Override
    public void del(Observer observer) {
        list.remove(observer);
    }
    // 给每一个观察者(订阅者)推送消息
    @Override
    public void notify(String message) {
        list.forEach(observer -> observer.update(message));
    }
 
}
    // 测试
    public static void main(String[] args){
      Observable o = new Subject();
      WeixinUser user1 = new WeixinUser("张三");
      WeixinUser user2 = new WeixinUser("李四");
      WeixinUser user3 = new WeixinUser("王五");
      o.add(user1);
      o.add(user2);
      o.add(user3);
      o.notify("薛之谦演唱会要来到广州啦!");
      // 运行结果
      // 张三接收到了消息(观察到了):薛之谦演唱会要来到广州啦!
      // 李四接收到了消息(观察到了):薛之谦演唱会要来到广州啦!
      // 王五接收到了消息(观察到了):薛之谦演唱会要来到广州啦!
    }
 

1.2 JDK实现

在 Java 中,通过java.util.Observable类和 java.util.Observer接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。

1.2.1 Observable类

Observable类是抽象目标类(被观察者),它有一个Vector集合成员变量,用于保存所有要通知的观察者对象,下面是它最重要的 3 个方法:
void addObserver(Observer o) 方法:用于将新的观察者对象添加到集合中。
void notifyObservers(Object arg) 方法:调用集合中的所有观察者对象的update方法,通知它们数据发生改变。通常越晚加入集合的观察者越先得到通知。
void setChange() 方法:用来设置一个boolean类型的内部标志,注明目标对象发生了变化。当它为true时,notifyObservers() 才会通知观察者。

1.2.2 Observer 接口

Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 update 方法,进行相应的工作。

1.2.3 代码实现

下面还是通过微信用户订阅公众号的例子进行代码实现,方便对比他们之间的区别:

// 具体的被观察者(公众号)
@Data
@AllArgsConstructor
public class Subject extends Observable {
    // 公众号的名字
    private String name;
    // 公众号发布消息
    public void notifyMessage(String message) {
        System.out.println(this.name + "公众号发布消息:" + message + "请关注用户留意接收!");
        super.setChanged();
        super.notifyObservers(message);
    }
}
@AllArgsConstructor
public class WeixinUser implements Observer {
    private String name;
    /**
     * @param o 被观察者
     * @param arg 被观察者带过来的参数,此例子中是公众号发布的消息
     */
    @Override
    public void update(Observable o, Object arg) {
        System.out.println(name + "关注了公众号(被观察者):" + ((Subject)o).getName() + ",接收到消息:" + arg);
    }
}
    // 测试
    public static void main(String[] args){
        WeixinUser user1 = new WeixinUser("张三");
        WeixinUser user2 = new WeixinUser("李四");
        WeixinUser user3 = new WeixinUser("王五");
        Subject subject = new Subject("演唱会消息发布");
        subject.addObserver(user1);
        subject.addObserver(user2);
        subject.addObserver(user3);
        subject.notifyMessage("薛之谦演唱会要来到广州啦!");
        // 返回结果
        // 演唱会消息发布公众号发布消息:薛之谦演唱会要来到广州啦!请关注用户留意接收!
        // 王五关注了公众号(被观察者):演唱会消息发布,接收到消息:薛之谦演唱会要来到广州啦!
        // 李四关注了公众号(被观察者):演唱会消息发布,接收到消息:薛之谦演唱会要来到广州啦!
        // 张三关注了公众号(被观察者):演唱会消息发布,接收到消息:薛之谦演唱会要来到广州啦!
    }

1.3 Google的Guava实现

在这里插入图片描述

@AllArgsConstructor
public class WeixinUser {
    private String name;
    @Subscribe
    public void getMessage(Object arg) {
        System.out.println(this.name + "接收到消息:" + arg);
    }
    // 测试
    public static void main(String[] args){
        // 消息总线
        EventBus eventBus = new EventBus();
        eventBus.register(new WeixinUser("张三"));
        eventBus.register(new WeixinUser("李四"));
        eventBus.post("薛之谦演唱会要来到广州啦!");
        // 返回结果
        // 张三接收到消息:薛之谦演唱会要来到广州啦!
        // 李四接收到消息:薛之谦演唱会要来到广州啦!
    }
}

1.4 总结

适用场景:

  • 当一个抽象模型包含两个方面内容,其中一个方面依赖于另一个方面。
  • 其他一个或多个对象的变化依赖于另一个对象的变化。
  • 实现类似广播机制的功能,无需知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。

多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。

优点:

  • 观察者和被观察者是松耦合(抽象耦合)的,符合依赖倒置原则。
  • 分离了表示层(观察者)和数据逻辑层(被观察者),并且建立了一套触发机制,使得数据的变化可以相应到多个表示层上。
  • 实现了一对多的通讯机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。

缺点:

  • 如果观察者数量过多,则事件通知会耗时较长。
  • 事件通知呈线性关系,如果其中一个观察者处理事件卡壳,会影响后续的观察者接收该事件。
  • 如果观察者和被观察者之间存在循环依赖,则可能造成两者之间的循环调用,导致系统崩溃。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘了个刘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值