23种设计模式(9):观察者模式

1.概念

观察者模式:定义对象间一种多对一的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

2.类图

在这里插入图片描述

在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。比如,我们要设计一个右键菜单的功能,只要在软件的有效区域内点击鼠标右键,就会弹出一个菜单;再比如,我们要设计一个自动保存的功能,就像IDEA开发时,只要修改了某几行代码,IDEA就会自动将修改的代码自动保存。这两个功能有一个相似的地方,那就是一个对象要时刻监听着另一个对象,只要它的状态一发生改变,自己随之要做出相应的行动。其实,能够实现这一点的方案很多,但是,无疑使用观察者模式是一个主流的选择。

3.观察者模式重要元素

  • 被观察者:从类图中可以看到,类中有一个用来存放观察者对象的CopyOnWriteArrayList容器(之所以使用CopyOnWriteArrayList,是因为多线程操作时,它在是安全的,而List则是不安全的),这个容器是被观察者类的核心,另外还有三个方法:addObserver方法是向这个容器中添加观察者对象;deleteObserver方法是从容器中移除观察者对象;notifyObserver方法是依次调用观察者对象的对应方法。这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多

  • 观察者:观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生变化时,这个方法就会被触发调用

  • 具体的被观察者:使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑。

  • 具体的观察者:观察者接口的具体实现,在这个角色中,将定义被观察者对象状态发生变化时,观察者对象所要处理的逻辑。

4.程式范例

观察者接口类

public interface Observer {
    //接收到改变通知时要进行的操作
   public void update();
}

观察者实现类A

public class ObserverA implements Observer{
    @Override
    public void update() {
        System.out.println("观察者A收到消息,要进行处理了...");
    }
}

观察者实现类B

public class ObserverB implements Observer{
    @Override
    public void update() {
        System.out.println("观察者B收到消息,开始进行处理了...");
    }
}

被观察者的抽象类

public abstract class AbstractObject {

    private CopyOnWriteArrayList<Observer> observerContainer = new CopyOnWriteArrayList<Observer>();

    public void addObserver(Observer observer) {
        this.observerContainer.add(observer);
    }

    public void deleteObserver(Observer observer) {
        this.observerContainer.remove(observer);
    }

    public void notifyObserver() {
        for (Observer o : observerContainer) {
            o.update();
        }
    }

    /**
     * 被监听者需要完成的业务操作
     */
    public abstract void dosomething();
}

被观察者的具体实现类

public class SpecificObject extends AbstractObject{
    @Override
    public void dosomething() {
        //这里完成特定的业务
        System.out.println("经过几个小时的奋战,终于又写出了一个bug");
        try {
            //模拟通知观察者的时间消耗
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.notifyObserver();
    }
}

用于测试的main方法

    public static void main(String[] args){
        SpecificObject specificObject = new SpecificObject();
        specificObject.addObserver(new ObserverA());
        specificObject.addObserver(new ObserverB());
        specificObject.dosomething();
    }

结果打印

经过几个小时的奋战,终于又写出了一个bug
观察者A收到消息,要进行处理了...
观察者B收到消息,开始进行处理了...

通过运行结果可以看到,我们只调用了specificObject的方法,但同时两个观察者的相关方法都被同时调用了。仔细看一下代码,其实很简单,无非就是在AbstractObject类中关联一下Observer类,并且在doSomething方法中遍历一下Observer的update方法就行了。

5.观察者模式的优点

观察者与被观察者之间是属于轻度的关联关系,并且是抽象耦合的,这样,对于两者来说都比较容易进行扩展。

观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。

6.观察者模式的缺点

但同时,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死。

以上时参考某大神的博客学习总结,附上原文链接:https://blog.csdn.net/zhengzhb/article/details/7471978

发布了46 篇原创文章 · 获赞 13 · 访问量 3027

猜你喜欢

转载自blog.csdn.net/weixin_45612794/article/details/104043678
今日推荐