设计模式之观察者模式

1. 观察者模式定义

  观察者模式:又称发布订阅模式,当一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。【引自百度百科】

 这里的目标物件,就是被观察者,当它的状态发生变更时,需要去通知所有观察它的观察者。

 根据定义大体就能知道,被观察者需要将一个个观察者管理起来,否则它怎么知道通知谁呢?这才是核心。

2. 类图

 自己感觉这个模式还是比较简单的,直接上类图吧:

这里写图片描述

该模式有四种角色:

  • Subject角色:被观察的对象,它实现了添加观察者和删除观察者的方法。另外,它还有一个notify方法用于通知所有的观察者。

  • ConcreteSubject角色:具体的观察者,这里视具体情况而定,感觉这个角色不是必须的。

  • Observer角色:它是一个接口,定义了update 方法,用于接受来着Subject角色的状态变化通知。

  • ConcreteObserver角色:表示具体的Observer,当它的update方法被调用后,表示已经被通知到,然后就可以在这个时机去处理变化。

3. 例子

 虽然简单,但还是举个小例子吧:

 假如有很多观察者,去观察一个会产生随机数字的对象,当产生随机数字的对象产生随机数时,就会通知对应的观察者,观察者将产生的数字打印出来。

 观察者有两类,一种观察者直接把数字显示,另一种观察者以简单的图形显示数值。

 首先定义NumberGenerator类,用于产生数值:

/**
 * the Observable
 */
public abstract class NumberGenerator {

    //核心:需要将观察者管理起来
    private ArrayList<Observer> observers = new ArrayList<>();

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

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    //核心:当自己状态变化时,需要通知所有的观察者
    public void notifyObservers() {
        Iterator<Observer> it = observers.iterator();
        while(it.hasNext()) {
            Observer o = it.next();
            o.update(this);
        }
    }

    public abstract int getNumber();

    public abstract void execute();

}

 再定义具体的被观察者类RandomNumberGenerator,用于产生随机数字:

/**
 * the concrete Observable
 */
public class RandomNumberGenerator extends  NumberGenerator {


    private int number;

    Random random = new Random();

    @Override
    public int getNumber() {
        return number;
    }

    @Override
    public void execute() {

        for(int i = 0; i < 20; i++) {
            number = random.nextInt(100);
            notifyObservers();
        }
    }
}

 接下来定义观察者接口Observer:

/**
 * observer
 */
public interface Observer {
    //NumberGenerator 相当于上下文,可以获取被观察者的一些信息
    void update(NumberGenerator generator);
}

 具体的观察者DigitObserver,只是打印普通的数字:

public class DigitObserver implements Observer{

    @Override
    public void update(NumberGenerator generator) {
        System.out.println("DigitObserver has  been notified, the number is :" + generator.getNumber());
    }
}

 具体的观察者GraphicObserver,以简单的图形展示数字:

/**
 * concrete observer
 */
public class GraphicObserver implements Observer {

    @Override
    public void update(NumberGenerator generator) {
        System.out.println("GraphicObserver has been notified, the number is :" + generator.getNumber());

        int count = generator.getNumber();

        for(int i =0; i < count; i++) {
            System.out.print("*");
        }

        System.out.println();
    }
}

 真正的客户端类:

    public class Main {

    public static void main(String[] args) {

        NumberGenerator generator  = new RandomNumberGenerator();

        Observer observer1 = new DigitObserver();
        Observer observer2 = new GraphicObserver();

        generator.addObserver(observer1);
        generator.addObserver(observer2);

        //被观察者获取数字并通知一堆被观察者
        generator.execute();
    }
}
4.总结

 这里被观察者去通知的时候根本不知道通知的具体是谁,它只认识Observer 接口的实例。这里体现了良好的扩展性。

 观察者并非主动的观察,而是被动的接受Subject角色的通知。

 JDK中也定义了Observable类和Observer接口,但是Observable是个具体的类,java又是单继承,导致复用性不好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值