设计模式(十一)观察者模式

设计模式概述见:
http://blog.csdn.net/chijiandi/article/details/78839305

观察者模式的基本概念

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

说简单点就是某人做某事 做完后要通知所有人让他们知道做了某事

什么时候使用观察者模式

观察者模式有这样几种使用场景:
1.当一个对象的改变需要导致未知个未知对象的改变时。
2.一个对象的改变必须通知其他对象。
3.对象改变时其他对象知道改变而不需要知道细节。
4.几个方面的互相依赖关系
5.功能链的触发,A导致B B导致C C导致D…..

举一个观察者模式的运用场景,比方说我们微博关注了某人,当某人发了新微博,关注的人就会得到通知,这就是一种发布-订阅。又比方说微信公众号也是这样的一种模式。

观察者模式怎么用

第一步:定义一个观察者的接口,接口仅要求有update方法

/**
 * @author : cjd
 * @Description :观察者接口
 * @create : 2018-03-19 13:14
 **/
public interface Observer {
    void update();
}

第二步:需要一个抽被观察者(需要通知的主题),他要求实体观察者持有增加观察者,移除观察者以及通知观察者的方法。

/**
 * @author : cjd
 * @Description : 抽象被观察者
 * @create : 2018-03-19 13:18
 **/
public abstract class Subject {
    //增加观察者
    public abstract void attachObserver(Observer o);

    //移除观察者
    public abstract void detachObserver(Observer o);

    //通知观察者
    public abstract void notifyObservers();
}

第三步:创建实体类被观察者,实现抽象被观察者的方法,第二步可视需要通知的主题内容情况省去,在实体类被观察者里是需要有一些自定义方法来判断是否进行通知以及通知的方式

/**
 * @author : cjd
 * @Description : 实体类的被观察者 被观察主题
 * @create : 2018-03-19 13:23
 **/
public class EntitySubject extends Subject {

    //存放观察者们的集合
    private ArrayList<Observer> observers;

    public EntitySubject() {
        observers = new ArrayList<>();
    }

    //若观察者不存在就添加
    @Override
    public void attachObserver(Observer o) {
        if(!(observers.contains(o))){
            observers.add(o);
        }
    }

    //若观察者存在就移除
    @Override
    public void detachObserver(Observer o) {
        if(observers.contains(o)){
            observers.remove(o);
        }
    }

    //通知所有观察者执行观察者的update方法
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

第四步:创建一个实体类的观察者,观察者需要能够主动去订阅主题的内容,需要实现具体的更新方法

/**
 * @author : cjd
 * @Description : 实体类观察者
 * @create : 2018-03-19 13:17
 **/
public class EntityObserver implements Observer {
    //观察者主动订阅主题
    public EntityObserver(Subject subject) {
        subject.attachObserver(this);
    }
    @Override
    public void update() {
        System.out.println("我被通知了");
    }
}

主函数这样进行一个观察与通知的调用:

/**
 * @author : cjd
 * @Description : 主函数
 * @create : 2018-03-19 13:35
 **/
public class Main {
    public static void main(String[] args) {
        //具体需要通知的主题
        Subject subject = new EntitySubject();
        //观察者订阅主题
        new EntityObserver(subject);
        //主题通知所有观察者
        subject.notifyObservers();
    }
}

第一步 根据需要通知的内容不同而实例化不同的主题
第二步 实例化不同的观察者来订阅某主题
第三部 调用主题的通知所有观察者即可

观察者主动移除主题与订阅相似。

后记

观察者模式的使用有如下的缺陷:
1.观察者与被观察者之间存在抽象的耦合,若观察者与被观察者之间存在循环关系,容易导致程序的崩溃。
2.当被观察者的数量比较多的时候,可能会出现通知缓慢的情况。
3.观察者只负责通知被观察者进行更新,而不知道具体如何更新。

所以在使用过程中,需要注意避免使用到相互循环,也因观察者若某一步骤导致终止会导致后续步骤不进行,所以应采用异步进行。

猜你喜欢

转载自blog.csdn.net/chijiandi/article/details/79553008