标准 专业
多元 极客

设计模式实验室(14)——观察者模式

什么是观察者模式?

观察者模式是一种对象行为型模式

观察者模式完美的将观察者和被观察的对象分开,它定义了对象建的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

观察者模式有很多种表现形式,比如消息队列中经常听到的发布订阅(Subscribe)模式,MVC复合设计模式中的模型-视图(Model-View)模式,事件监听器的源-收听者(Listener)模式。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。

核心结构

  • Subject。主题,代表了被观察的对象,在主题中定义一个观察者的集合,并提供添加、删除和通知观察者的方法,它可以是接口,也可以是抽象类。
  • ConcreteSubject。具体主题,是主题的子类,包括一些需要变化的对象或数据,当它的状态发生改变时,会调用通知方法向各个已经注册的观察者发出通知。
  • Observer。观察者,在具体主题发出通知后,观察者主要对通知作出适当的反应,一般的实现方式是接口,并定义相关的更新操作方法。
  • ConcreteObserver。具体观察者,主要是作用是观察者的具体实现,它存储了相关状态。

类图展示

观察者模式

代码分析

构建高可用的服务,消息队列是目前必不可少的中间价之一,除了消息队列常用的发布订阅模式,还有最基本的生产者消费者模式,接下来我们就以生产者消费者模式发送消息为例来实现观察者模式。

首先,我们定义一个主题,也就是消息生产者:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
 * 观察者模式——抽象主题
 */
public abstract class Producer {

    protected List<Consumer> observerList = new ArrayList<Consumer>();

    public void addObserver(Consumer consumer) {
        observerList.add(consumer);
    }

    public void removeObserver(Consumer consumer) {
        observerList.remove(consumer);
    }

    public abstract void produce();
}

接下来,我们定义一个抽象观察者,也就是消费者父类:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
 * 观察者模式——抽象观察者
 */
public abstract class Consumer {

    public abstract void send();
}

然后我们实现一个主题,也就是具体的消息生产对象:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
 * 观察者模式——具体主题
 */
public class MessageProducer extends Producer {

    @Override
    public void produce() {
        for (Consumer consumer : observerList) {
            consumer.send();
        }
    }
}

同时实现两个观察者,便于测试,也就是具体的消息消费对象:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
 * 观察者模式——具体观察者
 */
public class AndroidMessageConsumer extends Consumer {

    @Override
    public void send() {
        System.out.println("Channel is sending the message");
    }
}
/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
 * 观察者模式——具体观察者
 */
public class IOSMessageConsumer extends Consumer {

    @Override
    public void send() {
        System.out.println("APNS is sending the message");
    }
}

完活,接下来开始测试:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
 */
public class ObserverTest {

    public static void main(String[] args) {
        observerTest();
    }

    private static void observerTest() {
        try {
            Consumer consumerOne = new AndroidMessageConsumer();
            Consumer consumerTwo = new IOSMessageConsumer();
            Producer producer = new MessageProducer();
            producer.addObserver(consumerOne);
            producer.addObserver(consumerTwo);
            producer.produce();
            producer.removeObserver(consumerTwo);
            producer.produce();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

模式总结

优点

  • 主题和观察者间建立了一个抽象的耦合,主题主需要维护一个观察者集合,并不需要关注观察者的业务实现,实现了一定程度上的代码解耦。
  • 广播通信,降低了一对多系统的设计难度。
  • 符合开闭原则,如果需要对观察者进行扩展,仅需实现观察者接口并添加到主题维护的观察者集合中即可。
  • 代码实现更丰富,解放了具体观察者的实现限制,代码更多样化。

缺点

  • 如果观察者集合过大,可能会影响系统性能。
  • 如果观察者之间存在循环依赖,可能会造成循环调用导致内存溢出。
  • 观察者不清楚主题为什么发生了变化,仅知道是否发生了变化。

试用场景

  • 多个对象依赖于一个对象。

目前广泛应用于消息分发机制。

赞(0) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫