手机用户请
横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。
平台  | 地址  | 
|---|---|
CSDN  | https://blog.csdn.net/sinat_28690417  | 
简书  | https://www.jianshu.com/u/3032cc862300  | 
个人博客  | https://yiyuery.github.io/NoteBooks/  | 
观察者模式定义了对象之间的一对多依赖,这样依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并更新。
对于观察模式的实现方式有很多种,一般是以包含Subject和Observer接口的类设计做法最为常见。
根据多个观察者对于同一主题信息的获取方式,可以分为:
观察者模式的好处:
加入我们现在有个手机工厂,每次生产出一批手机后,就需要通知对应的代理商过来拿货。
我们就可以利用观察者模式来实现这个场景需求。
类图
public interface Observer<T> {
    /**
     * 观察者接收通知
     */
    void handle(T message);
}
public interface Subject<T> extends INotify{
    /**
     * 注册观察者
     * @param observer
     */
    void register(Observer<T> observer);
    /**
     * 注销观察者
     * @param observer
     */
    void cancel(Observer<T> observer);
}
public interface INotify {
    /**
     * 通知
     */
    void sendMessage();
}手机工厂
public class PhoneFactory implements Subject<Message> {
    private List<Observer<Message>> observers;
    /**
     * 消息体
     */
    private Message message;
    public PhoneFactory() {
        this.observers = new ArrayList<>();
    }
    /**
     * 注册观察者
     *
     * @param observer
     */
    @Override
    public void register(Observer<Message> observer) {
        observers.add(observer);
    }
    /**
     * 注销观察者
     *
     * @param observer
     */
    @Override
    public void cancel(Observer<Message> observer) {
        observers.remove(observer);
    }
    /**
     * 发送通知
     */
    @Override
    public void sendMessage() {
        observers.forEach(p->{
            p.handle(message);
        });
    }
    /**
     * 外部设置消息变更
     * @param message
     */
    public void setMessage(Message message) {
        this.message = message;
        sendMessage();
    }
}消息体
@Data
@Builder
@AllArgsConstructor
public class Message {
    /**
     * 消息体
     */
    private String data;
}代理商
//淘宝
public class TaobaoAgent implements Observer<Message> {
    /**
     * 观察者接收通知
     *
     * @param message
     */
    @Override
    public void handle(Message message) {
        System.out.println("Taobao receive message: " + message.getData());
    }
}
//天猫
public class TianmaoAgent implements Observer<Message> {
    /**
     * 观察者接收通知
     *
     * @param message
     */
    @Override
    public void handle(Message message) {
        System.out.println("Tianmao receive message: " + message.getData());
    }
}/**
 * 自定义观察者模式
 */
@Test
public void testX1() {
    //被观察者
    PhoneFactory phoneFactory = new PhoneFactory();
    //观察者
    TianmaoAgent tianmaoAgent = new TianmaoAgent();
    TaobaoAgent taobaoAgent = new TaobaoAgent();
    //注册
    phoneFactory.register(tianmaoAgent);
    phoneFactory.register(taobaoAgent);
    //发送通知
    phoneFactory.setMessage(Message.builder()
            .data("刚生产了100台Xiaomi手机")
            .build());
    //移除观察者
    phoneFactory.cancel(tianmaoAgent);
    //再次发送通知
    System.out.println("-------------------");
    phoneFactory.setMessage(Message.builder()
            .data("刚又生产了100台iPhone")
            .build());
}打印
Tianmao receive message: 刚生产了100台Xiaomi手机
Taobao receive message: 刚生产了100台Xiaomi手机
-------------------
Taobao receive message: 刚又生产了100台iPhone从输出可以看出,观察者和被观察者有以下几个特点:
那么思考下这个模式有没有什么不好的地方?
带着问题,我们来看下JDK内置的观察者模式怎么实现的?并看下如何实现主动拉取被观察者信息。
JDK内置观察者模式实现
public class PhoneFactory2 extends Observable {
    /**
     * 消息体
     */
    private Message message;
    public void setMessage(Message message) {
        this.message = message;
        setChanged();
        notifyObservers(message);
    }
    /**
     * 观察者按需主动拉取自己所需要信息
     * @return
     */
    public Message getMessage() {
        return message;
    }
}
public class TaobaoAgent2 implements Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param o   the observable object.
     * @param arg an argument passed to the <code>notifyObservers</code>
     */
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Taobao2 receive message: " + arg.toString());
    }
}
public class TianmaoAgent2 implements Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param o   the observable object.
     * @param arg an argument passed to the <code>notifyObservers</code>
     */
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Tianmao2 receive message: " + arg.toString());
    }
}比较下变化:
定义下测试类:
/**
 * 使用JDK原生观察者模式
 */
@Test
public void testX2() {
    //被观察者
    PhoneFactory2 phoneFactory = new PhoneFactory2();
    //观察者
    TianmaoAgent2 tianmaoAgent = new TianmaoAgent2();
    TaobaoAgent2 taobaoAgent = new TaobaoAgent2();
    //注册
    phoneFactory.addObserver(tianmaoAgent);
    phoneFactory.addObserver(taobaoAgent);
    //发送通知
    phoneFactory.setMessage(Message.builder()
            .data("刚生产了100台Xiaomi手机")
            .build());
    //移除观察者
    phoneFactory.deleteObserver(tianmaoAgent);
    //再次发送通知
    System.out.println("-------------------");
    phoneFactory.setMessage(Message.builder()
            .data("刚又生产了100台iPhone")
            .build());
    //主动拉取消息
    System.out.println("pull message:" + phoneFactory.getMessage());
}看下测试类的输出:
Taobao2 receive message: Message(data=刚生产了100台Xiaomi手机)
Tianmao2 receive message: Message(data=刚生产了100台Xiaomi手机)
-------------------
Taobao2 receive message: Message(data=刚又生产了100台iPhone)
pull message:Message(data=刚又生产了100台iPhone)分析下两次输出的区别:
其实乍看之下,两种方式实现结果貌似没什么区别,但是仔细观察JDK内置的Observable,不是一个接口,是个类。其内部的setChanged方法也是被 protected修饰的
protected synchronized void setChanged() {
        changed = true;
}这意味着:你除非继承自Observable,否则无法创建Observable实例,并组合到你自己的对象中来,这个设计违反了 多用组合,少用继承的设计原则。
相较于我们自己实现的观察者模式,可以结合泛型定义被通知的消息体,还可以结合我们的通知接口 INotify等方式来扩展,开发自由度更加高。但是无论是哪种方式,关键是熟悉观察者模式后,善用即可,
《Head First》读书笔记