观察者模式

2019-04-09  本文已影响0人  努力的土豆

开一个新的专题,开始记录关于设计模式的一些学习记录。本来觉得设计模式也就那么回事,看了一些源码,果断被打脸了。认认真真学习吧。

什么是观察者模式

观察者模式是软件设计的一种。在此种模式中,一个目标对象管理所有相依赖于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。


observe.jpg

参与类别

  1. 抽象目标类别
    此抽象类别提供一个界面让观察者进行添附与解附作业。此类别内部有不公开的观察者链,并透过下列方法进行作业。
  • 添附(Attach): 新增观察者到链中,以追踪目标对象的变化。
  • 解附(Detach): 将已经存在的观察者从链中移除。
  • 通知(Notify): 利用观察者所提供的更新函数来通知此目标已经产生变化。
  1. 目标类别
    此类别提供了观察者想要追踪的状态。也利用其源类别(抽象目标类别)所提供的方法,来通知所有的观察者其状态已经更新。此类别拥有如下方法。
  • 取得状态(GetState): 回传目标对象的状态。
  1. 抽象观察者界面
    抽象观察者类别是一个必须被实现的抽象类别。这个类别定义了所有观察者都拥有的更新界面,此界面是用来接收目标类别所发出的更新通知。此类别含有如下的方法。
  • 更新(Update): 会被实现的一个抽象方法。
  1. 观察者类别
    这个类别含有指向目标类别的参数(reference), 以接收来自目标类别的更新状态。此类别含有如下的方法。
  • 更新(Update): 是抽象方法的实现。当这个方法被目标对象调用时,观察者对象将会调用目标对象的取得状态(GetState)方法,来其所拥有的更新目标对象资讯。

每个观察者类别都要实现它的更新方法,以应对状态更新的情形。
当目标对象改变时,会通过调用它自己的通知方法来通知每一个观察者对象,这个通知方法则会去调用已经添附在链中的观察者更新方法。通知与更新方法可能会有一些参数,以方便指明是目前目标对象内的何种改变。这样实现可以增加观察者的效率。

用途

  1. 当抽象个体有两个互相依赖的层面时。封装这些层面在单独的对象内将可允许程序员单独地去变更与重复使用这些对象,而不会产生两者之前交互的问题。
  2. 当其中一个对象的变更会影响其他对象,却又不知道多少对象必须被同时变更时。
  3. 当对象应该有能力通知其他对象,又不应该知道其他对象的实现细节时。

观察者模式通常与MVC范式有关。在MVC中,观察者模式被用来降低model与view的耦合程度。一般而言,modle的改变会触发通知其他身为观察者的model。而这些model实际上是view,Java Swing就是一个范例,示意了modle预期会通过PropertyChangeNotification框架以送出改变的通知给其他的view。Model类别是Java bean类别的一员,并拥有与上述类别目标同样的行为。View类别则关联了GUI中的可视元素,并拥有与上述观察者类别同样的行为。当应用程序在执行时。使用者因view做出相应的更新而看见model所产的变化。

示例

模拟一个微信3D彩票服务号,和一些订阅者。

public interface Observer {

    void update(String msg);
}

public interface Subject {

    /**
     * 注册一个观察者
     * @param observer
     */
    void registerObserver(Observer observer);

    /**
     * 移除一个观察者
     * @param observer
     */
    void removeObserver(Observer observer);

    /**
     * 通知所有观察者
     * @param
     */
    void notifyObserver();
}

public class ObjectFor3D implements Subject {

    private List<Observer> observerList = new ArrayList<>();

    /**
     * 3D彩票号码
     */
    private String msg;

    @Override
    public void registerObserver(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        int index = observerList.indexOf(observer);
        if (index >= 0) {
            observerList.remove(index);
        }
    }

    @Override
    public void notifyObserver() {
        for (Observer observer: observerList) {
            observer.update(msg);
        }
    }

    public void setMsg(String msg) {
        this.msg = msg;
        notifyObserver();
    }
}
public class Observer1 implements Observer {

    private Subject subject;

    public Observer1(Subject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    @Override
    public void update(String msg) {
        System.out.println("observer1 得到 3D 号码 -->" + msg + "  haha");
    }
}

public class Observer2 implements Observer {

    private Subject subject;

    public Observer2(Subject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    @Override
    public void update(String msg) {
        System.out.println("observer2 得到 3D 号码 -->" + msg + "  hehie");
    }
}

public class Test {

    public static void main(String[] args) {
        ObjectFor3D subjectFoe3D = new ObjectFor3D();
        Observer1 observer1 = new Observer1(subjectFoe3D);
        Observer2 observer2 = new Observer2(subjectFoe3D);

        subjectFoe3D.setMsg("第一期中奖号码是: 123");
        subjectFoe3D.setMsg("第二期中奖号码是: 456");
    }
}
==============
结果
==============
observer1 得到 3D 号码 -->第一期中奖号码是: 123  haha
observer2 得到 3D 号码 -->第一期中奖号码是: 123  hehie
observer1 得到 3D 号码 -->第二期中奖号码是: 456  haha
observer2 得到 3D 号码 -->第二期中奖号码是: 456  hehie

示例2

感觉上面的例子不好,重新举个栗子。这里,设定一个不同用户接收短信的场景。这里以用户和短信发送发不同的角度分析。用户能够接收短信,首先,要有短息的发送方(假设是国内某个运营商),其次,用户还有接收短信的功能,这两个是最基本的条件,这也就对应上了观察者的。对于运营商来说,它要发短信,首先,它必须知道要发给谁,也就是要有一个用户列表(对应那些观察者),其次,要能够动态管理这些用户,譬如添加新的用户,删除欠费的用户(不让他/她接收短信),最重要的就是发送短信给用户了,这几点就对应了目标对象。下面上代码

/**
 * @Description: 这是一个抽象的观察者
 * @Param:  这里实现一个广播消息机制, Observe就是一个电信用户
 * @Return:
 * @Author: Kevin
 * @Date: 2019-04-19 15:46
 */
public interface Observe {

    String receiveMsg(String msg);
}

/**
 * @Description: 抽象的广播
 * @Param:  这里广播会有添加观察者,删除观察者,通知观察者的机制
 * @Return:
 * @Author: Kevin
 * @Date: 2019-04-19 15:47
 */
public interface Subject {

    void addObserve(Observe observe);

    void deleteObserve(Observe observe);

    void notifyAllOberves();
}

/**
 * @ClassName: MobelSubject
 * @Description: 这里假设是电信公司
 * @Author: kevin
 * @Date: 2019-04-19 15:50
 * @Version: 1.0
 */
public class MobelSubject implements Subject {

    /**
     * 这里是要发送信息的内容
     */
    private String message;

    /**
     * 这是是一个默认发短信的名单
     */
    private List<Observe> observeList = new ArrayList<>();

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public void addObserve(Observe observe) {
        observeList.add(observe);
    }

    @Override
    public void deleteObserve(Observe observe) {
        /**
         * 假设是存储位置
         */
        int index = observeList.indexOf(observe);
        if (index >= 0) {
            observeList.remove(index);
        }
    }

    @Override
    public void notifyAllOberves() {
        for (Observe observe: observeList) {
            observe.receiveMsg(this.message);
        }
    }
}

public class MobelObserveOne implements Observe {

    private Subject subject;

    /**
     * 接收的信息内容
     */
    private String msg;

    public MobelObserveOne(Subject subject) {
        this.subject = subject;
        subject.addObserve(this);
    }

    public void showMsg() {
        System.out.println("用户1,收到中国移动服务的信息是: " + this.msg);
    }

    @Override
    public String receiveMsg(String msg) {
        this.msg = msg;
        return this.msg;
    }
}

/**
 * @ClassName: MobelObserveOne
 * @Description: TODO
 * @Author: kevin
 * @Date: 2019-04-19 15:57
 * @Version: 1.0
 */
public class MobelObserveTwo implements Observe {

    private Subject subject;

    /**
     * 接收的信息内容
     */
    private String msg;

    public MobelObserveTwo(Subject subject) {
        this.subject = subject;
        subject.addObserve(this);
    }

    public void showMsg() {
        System.out.println("用户2,收到中国移动服务的信息是: " + this.msg);
    }

    @Override
    public String receiveMsg(String msg) {
        this.msg = msg;
        return this.msg;
    }
}

/**
 * @ClassName: MobelObserveOne
 * @Description: TODO
 * @Author: kevin
 * @Date: 2019-04-19 15:57
 * @Version: 1.0
 */
public class MobelObserveThree implements Observe {

    private Subject subject;

    /**
     * 接收的信息内容
     */
    private String msg;

    public MobelObserveThree(Subject subject) {
        this.subject = subject;
        subject.addObserve(this);
    }

    public void showMsg() {
        System.out.println("用户3,收到中国移动服务的信息是: " + this.msg);
    }

    @Override
    public String receiveMsg(String msg) {
        this.msg = msg;
        return this.msg;
    }
}

/**
 * @ClassName: Test
 * @Description: TODO
 * @Author: kevin
 * @Date: 2019-04-19 16:08
 * @Version: 1.0
 */
public class Test {
    public static void main(String[] args) {
        /**
         * 1 成立电信局
         */
        MobelSubject subject = new MobelSubject();

        /**
         * 2 注册用户
         */
        MobelObserveOne observeOne = new MobelObserveOne(subject);
        MobelObserveTwo observeTwo = new MobelObserveTwo(subject);
        MobelObserveThree observeThree = new MobelObserveThree(subject);

        /**
         * 3 电信局发送短信
         */
        subject.setMessage("欢迎您使用通信服务!!!");
        subject.notifyAllOberves();

        /**
         * 4 用户查看短信
         */
        observeOne.showMsg();
        observeTwo.showMsg();
        observeThree.showMsg();

    }
}
===================
结果
===================
用户1,收到中国移动服务的信息是: 欢迎您使用通信服务!!!
用户2,收到中国移动服务的信息是: 欢迎您使用通信服务!!!
用户3,收到中国移动服务的信息是: 欢迎您使用通信服务!!!

参考链接

观察者模式

设计模式 观察者模式 以微信公众服务为例

上一篇下一篇

猜你喜欢

热点阅读