设计模式之观察者模式


1.概念

观察者模式属于对象行为型模式,指的是当多个对象之间存在一对多的依赖关系时,当一个对象的状态或行为发生改变时,所有依赖它的对象会自动被触发更新操作,该模式又称之为发布-订阅模式,提到发布-订阅,不由得想到消息队列,是的,从广义上理解,他们之间有一丝相似之处。
观察模式中有几种角色:

  • 抽象观察目标(Subject):指被观察者对象观察的对象,观察目标应该持有所有观察者,自身状态发生改变后,应及时的将改变通知到观察者对象,观察者对象根据实际情况作出对应的改变行为
  • 抽象观察者(Observer):观察者需向被观察者对象提前注册自己的身份,以便被观察发生改变后,能够将改变通知到自己
  • 具体观察目标(ConcreteSubject):观察目标的具体实现
  • 具体观察者(ConcreteObserver):观察者的具体实现

处理以上四种角色之外,还应该有对事件的抽象机制:
抽象事件(Event):对事件的抽象描述
具体事件(ConcreteEvent):对事件的具体描述

增加抽象层是为了更好的规范和扩展,其实从水平方向简单来理解就是三个角色:

  1. 观察者
  2. 被观察者,也可以理解为观察者的管理对象
  3. 事件

再精简一下就是一句话:当被观察者发生改变时,通过事件的方式向观察者发布通知,观察者根据具体事件作出对应的行为。

以两个例子来简单说明:

张三开设了一个流浪宠物收容所,宠物园里有猫和狗两种宠物,每天要给收容所里的他们喂食,食物有鱼和骨头,张三的收容所就是被观察对象,收容所里收容了猫和狗,猫和狗就是观察者,而事件就是喂食这件事。张三每天向所有宠物们发布骨头和鱼,当食物准备好后,猫会选择吃鱼,而狗则会选择骨头,如果此次没有发布骨头,那狗什么也不干,继续观察。这里假设猫只吃鱼,狗只吃骨头。

再比如,居委会微信群里发布了一则消息,家里60岁以上的老人可以免费领取足力健,穿上足力健可以一步登泰山,这个消息可以看做是一个事件。群里的所有业主都会收到这个事件,但是不同的人群会根据事件作出不同的行为,比如家里所有人年龄加起来也没有60岁,对于这样的业主自然这不会理会这个事件,换成其他的消息呢,同样,业主们会根据消息的内容判断是否影响到自身,进而决定要不要作出改变。

丢一个UML图:
在这里插入图片描述
图片来源:百度图片


2.示例

以第一个简单示例来说明,首先观察目标的抽象和具体实现

/**
 * @description: 观察者管理接口 subject
 * @version: 1.0
 */
public interface PetsKeeper {

    void registerListener(Listener listener);

    void removeListener(Listener listener);

    void publishEvent(Event event);

}
/**
 * @description: 观察目标具体实现subject impl
 * @version: 1.0
 */
public class PetsKeeperImpl implements PetsKeeper {

    /*
    观察目标应持有所有依赖的观察者
     */
    private final Vector<Listener> listeners = new Vector<>();

    @Override
    public void registerListener(Listener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(Listener listener) {
        listeners.add(listener);
    }

    @Override
    public void publishEvent(Event event) {

        for (Iterator<Listener> it = listeners.iterator();it.hasNext();){
            Listener next = it.next();
            next.onEvent(event);
        }
    }

}

定义观察者和具体实现

public interface Listener {

    void onEvent(Event event);
}
public class CatListener implements Listener{
    @Override
    public void onEvent(Event event) {
        if (event instanceof FishEvent){
            System.out.println(event.getNotice() + "=>猫吃鱼");
        }
    }
}
public class DogListener implements Listener{
    @Override
    public void onEvent(Event event) {
        if (event instanceof BoneEvent){
            System.out.println(event.getNotice() + "=>狗吃骨头");
        }
    }
}

定义事件

/**
 * @description: 事件抽象层
 * @version: 1.0
 */
public abstract class Event {

    private String notice;

    public String getNotice() {
        return notice;
    }

    public void setNotice(String notice) {
        this.notice = notice;
    }
}

对事件分别做不同的实现

public class FishEvent extends Event{

    public FishEvent(String notice) {
        this.setNotice(notice);
    }
}
public class BoneEvent extends Event{

    public BoneEvent(String notice) {
        this.setNotice(notice);
    }
}

测试

/**
 * @description: test
 * @version: 1.0
 */
public class Test {
    public static void main(String[] args) {
        //创建观察者 分别是猫和狗
        Listener dogListener = new DogListener();
        Listener catListener = new CatListener();
        
        //创建宠物管理员
        PetsKeeper petsKeeper = new PetsKeeperImpl();

        //将宠物注册到宠物园 
        petsKeeper.registerListener(dogListener);
        petsKeeper.registerListener(catListener);

        //喂食 =>发布事件
        petsKeeper.publishEvent(new BoneEvent("啊哈哈啊,骨头来了"));
        petsKeeper.publishEvent(new FishEvent("啊哈哈啊,鱼来了"));
    }
}

input:

啊哈哈啊,骨头来了=>狗吃骨头
啊哈哈啊,鱼来了=>猫吃鱼

以上只是一个非常简单的示例,目的是为了说明观察者模式的原理和思想,实际业务中要根据实际的业务需求,适当的作出一些调整扩展,比如以上示例中是一个同步执行流程,被观察者发布事件后,如果观察者比较多,亦或执行流程比较复杂,观察目标需要一直等待所有观察者执行完毕才可以返回。故可以考虑将这这个流程处理为异步流程,具体做法可以在观察目标中维护一个事件的阻塞队列,开启异步线程。再比如,如果观察者处理发生异常呢?那可能还需要设计降级机制,或者反馈机制等。

需要注意的是,观察者和观察目标之间不能出现循环依赖,可能导致系统崩溃。
想象一下,猫狗吃法会触发喂食,喂食会触发猫狗吃饭,猫狗被撑死,人被累死,你这样子我们很难办啊,那就别办啦~

优点:观察者和被观察者是抽象耦合的,他们之间建立了一套触发机制
缺点:除了上边谈到问题,观察者只知道观察目标发生了变化,具体变化情况并不知道

3.总结

设计往往只是一个简单的思想描述,具体实现起来是多种多样的,而应用到业务中的实现,更应该充分考虑实际业务需求,对设计作出更好扩充优化,比如结合其他的设计模式,这一点是灵活的,好的设计应结合设计模式且脱离设计模式束缚,具体场景具体分析,切勿生搬硬套。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值