设计模式之禅-观察者模式

观察者模式

例子

韩非子和李斯。李斯监控韩非子,报信给秦王。
在这里插入图片描述

public interface IHanFeiZi {
    void haveBreakfast();
    void haveFun();
}
public interface Observable {
    void addObserver(Observer observer);
    void deleteObserver(Observer observer);
    void notifyObservers(String context);
}
public interface Observer {
    void update(String context);
}
public class HanFeiZi implements Observable,IHanFeiZi {
    private ArrayList<Observer> observerArrayList = new ArrayList<>();
    @Override
    public void addObserver(Observer observer) {
        this.observerArrayList.add(observer);
    }

    @Override
    public void deleteObserver(Observer observer) {
        this.observerArrayList.remove(observer);
    }

    @Override
    public void notifyObservers(String context) {
        for (Observer observer : observerArrayList) {
            observer.update(context);
        }
    }

    @Override
    public void haveBreakfast() {
        System.out.println("韩非子:开始吃饭");
        this.notifyObservers("韩非子在吃饭");
    }

    @Override
    public void haveFun() {
        System.out.println("韩非子:开始娱乐");
        this.notifyObservers("韩非子在娱乐");
    }
}
public class LiSi implements Observer {
    @Override
    public void update(String context) {
        System.out.println("李斯:观察到韩非子活动,开始向老板汇报了...");
        this.reportToQinShiHuang(context);
        System.out.println("李斯:汇报完毕...\n");
    }

    private void reportToQinShiHuang(String reportContext) {
        System.out.println("李斯:报告,秦老板!韩非子有活动了-->" + reportContext);
    }
}
public class LiuSi implements Observer {
    @Override
    public void update(String context) {
        System.out.println("刘斯:观察到韩非子活动,开始动作了...");
        this.happy(context);
        System.out.println("刘斯:乐死了\n");
    }

    private void happy(String context) {
        System.out.println("刘斯:因为" + context + ",--所以我快乐呀!");
    }
}
public class WangSi implements Observer {

    @Override
    public void update(String context) {
        System.out.println("王斯:观察到韩非子活动,自己也开始活动了...");
        this.cry(context);
        System.out.println("王斯:哭死了...\n");
    }

    private void cry(String context) {
        System.out.println("王斯:因为" + context + ",--所以我悲伤呀!");
    }
}
public class Client {
    public static void main(String[] args) {
        Observer liSi = new LiSi();
        Observer wangSi = new WangSi();
        Observer liuSi = new LiuSi();
        HanFeiZi hanFeiZi = new HanFeiZi();
        hanFeiZi.addObserver(liSi);
        hanFeiZi.addObserver(wangSi);
        hanFeiZi.addObserver(liuSi);
        hanFeiZi.haveBreakfast();
    }
}

定义

观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe)。定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
在这里插入图片描述

  • Subject被观察者
    定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类 或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。
  • Observer观察者
    观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。
  • ConcreteSubject具体的被观察者
    定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
  • ConcreteObserver具体的观察者
    每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。
public abstract class Subject {
    private Vector<Observer> observerVector = new Vector<>();
    public void addObserver(Observer o){
        this.observerVector.add(o);
    }
    public void delObserver(Observer o){
        this.observerVector.remove(o);
    }
    public void notifyObservers(){
        for (Observer o : this.observerVector) {
            o.update();
        }
    }
}
public class ConcreteSubject extends Subject{
    public void doSomething(){
        super.notifyObservers();
    }
}
public interface Observer {
    void update();
}
public class ConcreteObserver implements Observer{
    @Override
    public void update() {
        System.out.println("接收到信息,并进行处理!");
    }
}
public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer = new ConcreteObserver();
        subject.addObserver(observer);
        subject.doSomething();
    }
}

优点

  • 观察者和被观察者之间是抽象耦合
    不管是增加观察者还是被观察者都非常容易扩展,而且在Java中都已经实现的抽象层级的定义,在系统扩展方面更是得心应手。
  • 建立一套触发机制
    观察者模式可以完美地实现链条形式。

缺点

观察者模式需要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。 多级触发时的效率更是让人担忧。

使用场景

  • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
  • 事件多级触发场景。
  • 跨系统的消息交换场景,如消息队列的处理机制。

注意

  • 广播链的问题
    在一个观察者模式中 最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次),这还是比较好控制的。
  • 异步处理问题

扩展

java本身就有 java.util.Observablejava.util.Observer
在这里插入图片描述

public class HanFeiZi extends Observable implements IHanFeiZi {
    @Override
    public void haveBreakfast() {
        System.out.println("韩非子:开始吃饭了...");
        //通知所有的观察者
        super.setChanged();
        super.notifyObservers("韩非子在吃饭");
    }

    @Override
    public void haveFun() {
        System.out.println("韩非子:开始娱乐了...");
        super.setChanged();
        this.notifyObservers("韩非子在娱乐");
    }
}
public class LiSi implements Observer {
    @Override
    public void update(Observable o, Object object) {
        System.out.println("李斯:观察到韩非子活动,开始向老板汇报了...");
        this.reportToQinShiHuang(object.toString());
        System.out.println("李斯:汇报完毕...\n");
    }

    private void reportToQinShiHuang(String reportContext) {
        System.out.println("李斯:报告,秦老板!韩非子有活动了--->" + reportContext);
    }
}

大家看看我们使用了Java提供的观察者模式后 是不是简单了很多,所以在Java的世界里横行时,多看看API,有帮助很大,很多东西Java已经帮你设计了一个良好的框架。

项目中真实的观察者模式

  • 观察者和被观察者之间的消息沟通
    被观察者状态改变会触发观察者的一个行为,同时会传递一个消息给观察者,这是正确的,在实际中一般的做法是:观察者中的update方法接受两个参数,一个是被观察者,一个 是DTO(Data Transfer Object,据传输对象),DTO一般是一个纯洁的JavaBean,由被观察者 生成,由观察者消费。 当然,如果考虑到远程传输,一般消息是以XML格式传递。
  • 观察者响应方式
    一是采用多线程技术,甭管是被观察者启动线程还是观察者启动线程,都可以明显地提高系统性能,这也就是大家通常所说的异步架构;二是缓存技术,准备了足够的资源,保证快速响应,这当然也是一种比较好方案,代价就是开发难度很大,而且压力测试要做的足够充 分,这种方案也就是大家说的同步架构。
  • 被观察者尽量自己做主
    对被观察者的业务逻辑 doSomething方法实现重载,如增加一个doSomething(boolean isNotifyObs)方法,决定是否通知观察者,而不是在消息到达观察者时才判断是否要消费。

最佳实践

  • 文件系统
    比如,在一个目录下新建立一个文件,这个动作会同时通知目录管理器增加该目录,并通知磁盘管理器减少1KB的空间,也就说“文件”是一个被观察者,“目录管理器”和“磁盘管理器”则是观察者。
  • 广播收音机
    电台在广播,你可以打开一个收音机,或者两个收音机来收听,电台就是被观察者,收音机就是观察者。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值