设计模式《观察者模式》

2018-07-13  本文已影响0人  天道__

引言

  开弓没有回头箭,我们还的继续,回顾上一节我们讲的建造者模式,这节我们说说观察者模式。

示例地址

  Demo

类图

image

定义

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

使用场景

   1.关联行为场景,需要注意的是,关联行为是可拆分的,而不是"组合"关系;
   2.事件多级触发场景;
   3.跨系统的消息交换场景,例如消息队列、事件总线的处理机制。

观察者模式中的两个角色

  Observer: 观察者角色。
  Observable:被观察者角色。

观察者模式示例

  举个栗子,我们在上班的时候,每个公司或者每个楼都有烟感设备,一旦抽烟或者楼道发生火灾,第一立刻鸣警,第二,装备里面的水银自断,立刻喷水。这个例子中,观察者是烟感设备,被观察者是烟或者火。

1. 定义观察者接口
/**
 * 观察者接口
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午10:38.
 */
public interface IObserver {
    //更新消息
    void updateMessage(String message);
}
2. 观察者的实现(烟感应器)
/**
 * 烟感应器
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午11:05.
 */
public class YanObserver implements IObserver {

    @Override
    public void updateMessage(String message) {
        System.out.println(message + "烟感应器 感应到了火情,立刻鸣警");
    }
}
3. 观察者的实现(水银感应器)
/**
 * 水银感应器
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午11:08.
 */
public class ShuiYinObserver implements IObserver {
    @Override
    public void updateMessage(String message) {
        System.out.println(message + "水银感应器 感应到了火情,立刻自毁水银,开始喷水");
    }
}
4. 被观察者接口
/**
 * 被观察者接口
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午10:39.
 */
public interface IObservable {
    //添加
    void addObserver(IObserver observer);

    //移除
    void removeObserver(IObserver observer);

    //通知
    void noticeObserver(String messgae);
}
5. 被观察者实现(着火)
/**
 * 发生火情
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午11:23.
 */
public class ZhaoHuo implements IObservable {

    private List<IObserver> mIObservers = new ArrayList<>();

    @Override
    public void addObserver(IObserver observer) {
        if (!mIObservers.contains(observer)) {
            mIObservers.add(observer);
        }
    }

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

    @Override
    public void noticeObserver(String messgae) {
        for (IObserver observer : mIObservers) {
            observer.updateMessage(messgae);
        }
    }

    public void change(String messgae) {
        System.out.println("推模型---------");
        noticeObserver(messgae);
    }
}
6. Client调用
ZhaoHuo zhaoHuo = new ZhaoHuo();

//烟感设备
IObserver yanObserver = new YanObserver();
IObserver shuiYinObserver = new ShuiYinObserver();

//添加观察者
zhaoHuo.addObserver(yanObserver);
zhaoHuo.addObserver(shuiYinObserver);

//通知
zhaoHuo.change("着火了 !");

推模型和拉模型概念

  在观察者模式中,又分为推模型和拉模型两种方式。

1. 推模型

  主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。

2. 拉模型

  主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。

推模型和拉模型二者的比较

  1、推模型是假定目标对象知道观察者需要的数据;拉模型不知道observer需要什么数据,因此把自身传给observer,由观察者来取值
  2、推模型使observer对象难以复用,拉模型传递的是目标对象本身,满足各种需要

拉模型的示例

  上面那个烟感设备就是典型的推模型,下面我们来看看拉模型的实现

1. 观察者接口(这里主要讲参数变成被观察者本身了)
/**
 * 观察者接口
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午10:38.
 */
public interface IObserver {
    //更新消息
    void updateMessage(IObservable observable);
}
2.烟感应器

/**
 * 烟感应器
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午11:05.
 */
public class YanObserver implements IObserver {

    @Override
    public void updateMessage(IObservable observable) {
        String message=((ZhaoHuo)observable).getMessage();
        System.out.println(message + "烟感应器 感应到了火情,立刻鸣警");
    }
}
3. 水银感应器
/**
 * 水银感应器
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午11:08.
 */
public class ShuiYinObserver implements IObserver {

    @Override
    public void updateMessage(IObservable observable) {

         String message=((ZhaoHuo)observable).getMessage();
        System.out.println(message + "水银感应器 感应到了火情,立刻自毁水银,开始喷水");
    }
}
4. 被观察者接口(通知中不传递任何参数)
/**
 * 被观察者接口
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午10:39.
 */
public interface IObservable {
    //添加
    void addObserver(IObserver observer);

    //移除
    void removeObserver(IObserver observer);

    //通知
    void noticeObserver();
}
5. 发生火情(自身作为参数传递)
/**
 * 发生火情
 *
 * @author 512573717@qq.com
 * @created 2018/7/18  上午11:23.
 */
public class ZhaoHuo implements IObservable {

    private String message;

    private List<IObserver> mIObservers = new ArrayList<>();

    @Override
    public void addObserver(IObserver observer) {
        if (!mIObservers.contains(observer)) {
            mIObservers.add(observer);
        }
    }

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

    @Override
    public void noticeObserver() {
        for (IObserver observer : mIObservers) {
            // 将自身作为参数传递
            observer.updateMessage(this);
        }
    }

    public void change(String message) {
        message = message;
        System.out.println(" 拉模型:" + message);
        //状态发生改变,通知各个观察者
        this.noticeObserver();
    }


    public String getMessage() {
        return message;
    }
}

6. Client
  ZhaoHuo zhaoHuo = new ZhaoHuo();

        //烟感设备
        IObserver yanObserver = new YanObserver();
        IObserver shuiYinObserver = new ShuiYinObserver();

        //添加观察者
        zhaoHuo.addObserver(yanObserver);
        zhaoHuo.addObserver(shuiYinObserver);

        //通知
        zhaoHuo.change("着火了 !");

总结

  观察者模式定义的是一对多的依赖关系,一个被观察者可以拥有多个观察者,并且通过接口对观察者与被观察者进行逻辑解耦,降低二者的直接耦合。
  1. 针对观察者与被观察者分别定义接口,有利于分别进行扩展。
  2. 定义观察者集合,并定义针对集合的添加、删除操作,用于增加、删除订阅者(观察者
  3. 定义通知方法,用于将新情况通知给观察者用户(订阅者用户)
  4、观察者中需要有个接收被观察者通知的方法。

上一篇 下一篇

猜你喜欢

热点阅读