观察者模式(设计模式之观察者模式)

1.设计模式之终极结合

今天星期五了(异常的兴奋,周末又可以去**了,提前祝大家周末愉快),完成项目经理的需求之后开始继续最近几期博客的编写。承接上一篇博客单例模式,这一期我们一起来了解一下观察者模式。我们最近几期博客打算主要讲一下单例模式、观察者模式、Build模式,目的是为了方便后期为大家带来RXJava+Retrofit2.0+Okhttp3结合使用的网络请求框架。

周末两天过的真快,不过我一直在想我怎么才能写的简单明了,写出观察者模式的精华。

2.观察者模式定义

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

3.观察者模式理解

一个被观察者对象(ConcreteObservable也被叫为具体的主题ConcreteSubject)可以有一个或多个观察者(Observer)。观察者(这里说的就是具体观察者ConcreteObserver)可以是实现了 观察者(Observer) 接口的任意对象。一个 observable 实例改变后,调用 观察者(observable) 的notifyObservers()方法的应用程序会通过调用观察者的update() 方法来通知观察者该实例发生了改变。

是不是感觉有点没理过来,很混乱。其实简单理解观察者模式就是:1个抽象的被观察者(java中的一个类Observable)和多个抽象的观察者(java中的一个接口Observer)两者之间的订阅——发布的关系;抽象的东西只是概念,所以我们要具体化,具体到我们的项目中的对象;就有了具体主题(ConcreteSubject 继承了观察者{Observable}类)和具体的观察者(ConcreteObserver实现了观察者{Observer}接口)。

如果这样还是不好理解,我们就来个具体的例子,比如我们现在的微信公众号(把它认为是具体的主题继承了被观察者对象)以及很多微信用户(把它认为是具体的观察者实现 了观察者接口);我们用户只要订阅了某微信公众号,那么只要微信公众号发布信息,我们用户就会收到消息并调用更新方法(update())。这样一个关系叫观察者模式(更喜欢叫它为订阅——发布的模式)。

4.UML类图

观察者模式(设计模式之观察者模式)_第1张图片

观察者方法说明:

  • update(Observable o,Object arg) 

          只要改变了 observable 对象就调用此方法。

被观察者方法说明:

  • notifyObservers(Object arg) 

          通知其所有观察者,内容发生变化。

  • addObserver(Observer o) 

          如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。

  • deleteObserver(Observer o) 

          从对象的观察者集合中删除某个观察者。

角色介绍:

  • Subject(抽象主题):被观察者(Observable)的角色,抽象主题角色把所有观察者对象的引用都存入这个集合里,每个主题都可以有任意数量的观察者,抽象主题提供几个方法,可以增加和删除观察者对象以及通知观察者对象内容发生变化。
  • ConcreteSubject(具体主题):具体被观察者(ConcretObservable),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有订阅过的观察者发出通知。
  • Observer(抽象观察者):观察者的抽象接口,该角色只有一个update()更新方法,当收到通知内容后更新自己的内容。
  • ConcreteObserver(具体观察者):该角色实现了抽象观察者接口,当收到主题的状态改变时更新自己的内容。

5.JAVA API 

  • Observer(观察者接口Interface):

观察者模式(设计模式之观察者模式)_第2张图片

  •  Observable(被观察者) 

观察者模式(设计模式之观察者模式)_第3张图片

 

观察者模式(设计模式之观察者模式)_第4张图片

6.观察者模式简单示例

思前想后,我到底要做个什么例子啦,微信公众号——微信用户的(发布与订阅关系),确实比较贴近生活;但是好像这个例子有点烂大街了。我就做个项目经理(被观察者)——技术部员工(一群观察者,当然你说可不可只有一个技术人员了也可以的,全栈)这个例子吧;这个也挺好理解的吧,你被录用分配到技术部,不管你负责前端、后端、后台、数据库、还是美工;这样你们就要听项目经理的安排(订阅了),经理今天发布通知:必须在周5完成这个项目上线(发布)。是不是大家都受到消息开始干自己的事情,知道有一天前端干不下去了,离职了,是不是就解除这个订阅关系,不再受到通知。那么让我们一起来看代码: 

  • StaffObserver(具体观察者)
import java.util.Observable;
import java.util.Observer;

/**
 * 员工观察者角色
 */
public class StaffObserver implements Observer {
    private String staff;
    private String leader;
    LeaderSubject leaderSubject = new LeaderSubject("项目经理");
    public StaffObserver(String s) {
        staff = s;
    }

    @Override
    public void update(Observable observable, Object o) {
        System.out.println(staff+"接受到"+leader+"发送通知:"+o);
    }

    public void update(String str,Object o){
        leader = str;
        update(leaderSubject,o);
    }
}
  • LeaderSubject(具体被观察者)
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;

/**
 * 领导主题角色继承被观察者
 */
public class LeaderSubject extends Observable {
    private List mList;
    private String leader;
    public LeaderSubject(String s) {
        leader = s;
        this.mList = new ArrayList();
    }
    /**
     *
     * @param o 删除具体观察者
     */
    public synchronized void deleteObserver(StaffObserver o) {
        super.deleteObserver(o);
        if(mList != null && mList.size()>0){
            mList.remove(o);
        }
    }

    /**
     *
     * @param o 增加具体观察者
     */
    public synchronized void addObserver(StaffObserver o) {
        super.addObserver(o);
        if(mList !=null){
            mList.add(o);
        }

    }

    /**
     * 当调用setChanged(String msg)调用具体实现
     * @param msg
     */
    @Override
    public void notifyObservers(Object msg) {
        super.notifyObservers(msg);
        if(mList != null){
            for (StaffObserver s:mList) {
                s.update(leader,msg);
            }

        }
    }

    /**
     * 被观察者内容发生改变
     * @param msg 改变的内容
     */
    public  void setChanged(String msg) {
        //消息更新,通知所有观察者
        notifyObservers(msg);
    }
}
  • TestObserver(实现类)
public class TestObserver {
    public static void main(String[] args) {

        LeaderSubject leaderSubject = new LeaderSubject("项目经理");
        StaffObserver frontEnd = new StaffObserver("FrontEnd");
        StaffObserver Database = new StaffObserver("Database");
        StaffObserver UI = new StaffObserver("UI");


        leaderSubject.addObserver(frontEnd);
        leaderSubject.addObserver(Database);
        leaderSubject.addObserver(UI);
        leaderSubject.setChanged("这周我们完成这个项目,并上线!");

        leaderSubject.deleteObserver(UI);
        System.out.println("------------------观察者减少");
        leaderSubject.setChanged("由于美工的离职,我们延迟上线!");

    }
}
  • AS输出结果:

观察者模式(设计模式之观察者模式)_第5张图片

  • 记事本DOS命令输出结果: 

观察者模式(设计模式之观察者模式)_第6张图片

是不是很简单,就1个具体观察者类和1个具体被观察这类,然后就是具体的实现类;员工的增加与减少不影响其他员工接受通知。在这个过程中整个流程都是依赖Observer和Observable这些抽象接口和类,所以StaffObserver和LeaderSubject完全没有耦合,保证了整个系统的灵活性和可拓展性。

这就达到了我们解耦的效果了,观察者模式。

7.观察者模式总结

优点:

观察者和被观察者没有耦合,增强了系统灵活性和可拓展性。

缺点:

被观察者是按顺序执行,如果业务负责,被观察者很多,那么就会影响效率;同时如果其中一个卡顿会影响后面的观察者,所以我们建议这种情况使用异步任务。

8.更多请关注持续更新

现在其实有很多观察者模式的具体实现:比如我们的Android源码BaseAdapter,开源框架EventBus,以及RxJava等等。

如果想看的人多,我们会在这篇博客下继续更新EventBus和Rxjava的简单讲解以及源码分析。

你可能感兴趣的:(设计模式,Java)