观察者模式(Observer)

本文介绍了观察者模式在软件设计中的应用,通过将目标主题设置为主动方,观察者变为被动方,优化了一对多关系中的状态更新同步。以商店机票降价为例,说明了传统方式中买家频繁查询的低效,对比引入观察者模式后的高效通知机制。观察者模式包括Subject(目标主题)、ConcreteSubject(主题实现)、Observer(观察者)和ConcreteObserver(观察者实现)四个角色。代码示例展示了如何使用Java实现这一模式。

发布/订阅

现实中的观察者(Observer)往往是主动方,这是由于目标主题(Subject)缺乏主观能动性造成的,其状态的更新并不能主动地通知观察者,这就造成观察行为的持续往复。而在软件设计中我们可以将目标主题作为主动方角色,将观察者反转为被动方角色,建立反向驱动式的消息响应机制,以此来避免做无用功,优化软件效率

作为一种发布/订阅(publish/subscribe)式模型,观察者模式被大量应用于具有一对多关系对象结构的场景,它支持多个观察者订阅一个目标主题。一旦目标主题的状态发生变化,目标对象便主动进行广播,即刻对所有订阅者(观察者)发布全员消息通知,

基于这种一对多的关系网,观察者模式以多态化(泛型化)的方式弱化了目标主题与观察者之间强耦合的依赖关系,标准化它们的消息交互接口,并让主客关系发生反转,以“单方驱动全局”模式取代“多方持续轮询”模式,使目标主题(单方)的任何状态更新都能被即刻通过广播的形式通知观察者们(多方),解决了状态同步知悉的效率问题。

业务场景

商店的机票降价了?

未使用观察者模式,需要买家一直询问商店机票是否降价,往往需要耗费大量的无用功

引入观察者模式

观察者,买家,买家如果需要购买商店降价机票,需要在商店订阅机票情况

被观察者,商店机票价格,定义买家清单,后续机票降价时会通知所有订购的买家

以观察者为主动方的设计缺陷,大量无用功被消耗在状态交互上,举例机票是否降价,每次都得去点击刷新页面查看机票是否降价,频繁轮训处于被动状态,消耗大量无用功,换种做法,逆向思维,反客为主,当机票降价时,通知用户下单购买

这种反客为主的设计只需要一次握手协议并建立连接通道即可完成,之后发生的状态更新完全可以由服务端(被观察者)向Web客户端(观察者)进行消息推送的方式完成,这时就不会再有频繁轮询的情况发生了,交互效率问题迎刃而解

观察者模式的各角色定义如下

● Subject(目标主题):被观察的目标主题的接口抽象,维护观察者对象列表,并定义注册方法register()(订阅)与通知方法notify()(发布)。Shop

● ConcreteSubject(主题实现):被观察的目标主题的具体实现类,持有一个属性状态State,可以有多种实现。Shop

● Observer(观察者):观察者的接口抽象,定义响应方法update()。对应本章例程中的买家类Buyer。Buyer

● ConcreteObserver(观察者实现):观察者的具体实现类,可以有任意多个子类实现。收到通知后进行自己独特的处理。AirCustomer

 实例代码

package com.azure.design.observer;

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

/**
 * 商店类
 */
public class Shop {

    private String product;

    private List<Buyer> buyers; //预订清单

    public Shop() {
        this.product = "无降价";

        this.buyers = new ArrayList<>();
    }

    //注册买家到预订清单中
    public void register(Buyer buyer) {
        this.buyers.add(buyer);
    }


    public String getproduct() {
        return product;
    }

    public void setproduct(String product) {

        this.product = product; //到货了
        notifyBuyers(); //到货后通知买家
    }

    // 通知所有的买家
    private void notifyBuyers() {
        buyers.stream().forEach(b -> b.inform(this.getproduct()));
    }
}
package com.azure.design.observer;

/**
 * 买家抽象类
 */
public abstract class Buyer {

    protected String name;

    public Buyer(String name) {
        this.name = name;
    }

    public abstract void inform(String product);
}
package com.azure.design.observer;

public class AirCustomer extends Buyer{

    // 调用父类构造器
    public AirCustomer(String name) {
        super(name);
    }

    @Override
    public void inform(String product) {
        if(product.contains("机票")) {
            System.out.print(name);
            System.out.println("购买:" + product);
        }
    }
}
public class Client {

    @Test
    public void testObserverDemo() {
        Buyer buyer = new AirCustomer("抢机票黄牛");
        Shop shop = new Shop();
        // 商店注册信息,预定
        shop.register(buyer);
        // 商店中机票降价
        shop.setproduct("机票降价了");
    }

}

程序输出

//抢机票黄牛购买:机票降价了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值