观察者模式 一

简单实例

首先看一个警察蹲点抓小偷的简单实例:警察蹲点观察到小偷偷东西就立即抓捕

Policemen.Java (警察)

public class Policemen implements Observer {

    /**
     * 警察姓名
     */
    private String name;

    public Policemen(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        Pickpocket pickpocket = (Pickpocket) o;

        System.out.printf("警察 %s 发现(实际是被通知)扒手 %s 盗取了 %s,立即抓捕 \n", this.name, pickpocket.getName(), arg);
    }
}

Pickpocket.java (扒手)

public class Pickpocket extends Observable {

    /**
     * 小偷姓名
     */
    private String name;

    /**
     * 赃物
     */
    private List booties = new ArrayList<>();

    public Pickpocket(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    /**
     * 偷窃
     * @param booty
     */
    public void steal(String booty) {
        booties.add(booty);

        setChanged();
        notifyObservers(booties);
    }
}

ObserverEx1Test.java (测试类)

public class ObserverEx1Test {

    public static void main(String[] args) {
        Policemen p1 = new Policemen("警察A");
        Policemen p2 = new Policemen("警察B");
        Pickpocket pp1 = new Pickpocket("郭某");

        pp1.addObserver(p1);
        pp1.addObserver(p2);

        pp1.steal("cellphone");
    }
}

运行ObserverEx1Test类输出结果:

警察 警察B 发现(实际是被通知)郭某 盗取了 [cellphone] ,立即抓捕
警察 警察A 发现(实际是被通知)郭某 盗取了 [cellphone] ,立即抓捕

上边这种例子观察者模式叫:发布-订阅模式

观察者模式介绍

定义

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

解决的问题

一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

优点

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
  • 目标与观察者之间建立了一套触发机制。

缺点

  • 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
  • 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

使用场景

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

简单实例 二

由于java.util.Observable 和 java.util.Observer 类在java9 之后过期了,该实例主要是不再继承java.util.Observable 和 java.util.Observer 实现观察者模式

IObserver.java 接口

public interface IObserver {

    /**
     * 观察者获得消息
     * @param msg
     */
    void update(String msg);
}

ISubject.java 接口

public interface ISubject {

    /**
     * 注册观察者
     * @param observer
     */
    void registerObserver(IObserver observer);

    /**
     * 取消观察者
     * @param observer
     */
    void removeObserver(IObserver observer);

    /**
     * 通知观察者
     */
    void notifyObserver();

    /**
     * 获取主体标示名称
     * @return
     */
    String getName();

}

Pickpocket.java

public class Pickpocket implements ISubject {

    /**
     * 小偷姓名
     */
    private String name;

    /**
     * 赃物
     */
    private String booty;

    /**
     * 观察者集合
     */
    private List observers = new ArrayList<>();

    public Pickpocket(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void registerObserver(IObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(IObserver observer) {
        if (observers.contains(observer)) {
            observers.remove(observer);
        }
    }

    @Override
    public void notifyObserver() {
        for (IObserver observer : observers) {
            observer.update(booty);
        }
    }

    /**
     * 盗取赃物后给观察者(警察)发送消息
     * @param booty
     */
    public void steal(String booty) {
        this.booty = booty;
        // 通知观察者
        notifyObserver();
    }

}

Policemen.java

public class Policemen implements IObserver {

    /**
     * 警察姓名
     */
    private String name;

    /**
     * 增具体的观察者订阅的主体
     */
    private ISubject subject;

    public Policemen(String name, ISubject subject) {
        this.name = name;
        this.subject = subject;
        subject.registerObserver(this);
    }

    @Override
    public void update(String booty) {

        System.out.printf("警察 %s 发现(实际是被通知)%s 盗取了 %s ,立即抓捕\n", this.name, subject.getName(), booty);
    }
}

ObserverEx1Test.java

public class ObserverEx1Test {

    public static void main(String[] args) {
        Pickpocket pp = new Pickpocket("Pickpocket-A");

        Policemen p1 = new Policemen("Policemen-A", pp);
        Policemen p2 = new Policemen("Policemen-B", pp);

        pp.steal("手机");

        System.out.println("------------------------");
        pp.removeObserver(p2);
        pp.steal("PAD");
    }
}

执行结果:

警察 Policemen-A 发现(实际是被通知)Pickpocket-A 盗取了 手机 ,立即抓捕
警察 Policemen-B 发现(实际是被通知)Pickpocket-A 盗取了 手机 ,立即抓捕
------------------------
警察 Policemen-A 发现(实际是被通知)Pickpocket-A 盗取了 PAD ,立即抓捕

你可能感兴趣的:(观察者模式 一)