java常用设计模式(三)观察者模式

  设计模式第三篇,观察者模式,大家多多指教

简介

  观察者模式定义了对象之间的一组一对多的依赖,当一个对象改变时,其他被依赖的对象都会收到通知并且自动更新(引自《Head First设计模式》)。首先观察者模式有一个对象,我们称之为主题对象(Subject),有很多其他的对象我们称之为观察者(Observer),主题对象和观察者是一对多的关系,当主题对象发生改变时,观察者会收到来自于主题对象的通知,并根据通知做出相应的操作。在这里有一个需要注意的地方,那就是一个对象要成为观察者或者不想做观察者了,都需要告知主题对象,主题对象会更新一对多的这个依赖关系,由此可见主题对象应该维护的有一个观察者列表。

JDK内置的观察者模式

  JAVA API内置的观察者模式分别是java.util.Observable类和java.util.Observable接口。要实现观察者模式只需要把主题对象继承java.util.Observable类,把观察者实现java.util.Observable接口。下面我们通过一个例子来展示观察者模式的工作过程,例子的场景是某个社区提问的过程:

  第一步:新建一个问题类,定义两个成员变量分别是提问人和问题的内容

/*
 * 问题
 */
public class Question {
    /** 提问人 */
    private String name;
    /** 问题内容 */
    private String question;

    public Question(String name, String question) {
        this.name = name;
        this.question = question;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getQuestion() {
        return question;
    }

    public void setQuestion(String question) {
        this.question = question;
    }
}

  第二步:新建主体对象,此处的主体对象应该是社区,社区类继承Observable类,提问方法是publishQuestion,此处会设置主体对象为已改变,并且通知所有的观察者

/*
 * 社区对象
 */
public class Community extends Observable {
    private static Community community;

    private Community(){
        if(community != null){
            throw new RuntimeException("不要想反射攻击我");
        }
    }

    public static Community getInstance(){
        if(community == null){
            community = new Community();
        }
        return community;
    }

    public void publishQuestion(Question question){
        System.out.println(question.getName()+"在社区提了提了一个问题,问题内容是:"+ question.getQuestion());
        /** 设置主体对象的状态为已改变 */
        setChanged();
        /** 通知所有的观察者 */
        notifyObservers(question);
    }
}

  第三步:新建观察者为社区的工作人员,负责解决问题,观察者要实现Observer接口

public class Worker implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        Community community = (Community) o;
        Question question = (Question) arg;

        System.out.println("==================");
        System.out.println("收到来自社区的一个提问,提问人是:"+ question.getName());
        System.out.println("内容是:"+ question.getQuestion());
    }
}

   第四步:注册观察者,把观察者和主题对象关联起来

public class ObserverTest {

    public static void main(String[] args) {
        Community community = Community.getInstance();
        Question question = new Question("张三","几点上班?");
        /** 观察者注册 */
        community.addObserver(new Worker());
        community.publishQuestion(question);
    }

}

番外

  上面的观察者模式的实现是由主题对象往观察者去“推消息“,即主题对象主动去通知观察者(Community去通知Worker) ,其实这种java API还支持观察者去主题对象去“拉消息”,这种做法和推各有特点,推的好处是由主题对象去控制推的时机和内容,能够一次性把所有的东西推给观察者,但是对于不同的观察者而言有种一视同仁的感觉,如果所有观察者需要的信息并不一致的话,就需要去推更多的内容,这其中必定包含一些冗余的消息。拉的好处是能够由观察者自主的去选择需要的内容和时机,这样观察者能够只拉自己想要的东西,而且由于时间又观察者定,主题对象和观察者之间的交互就不会有那么频繁,但是这样的话主题对象必须把自己“暴露”给观察者,而且收集到的信息可能不全,需要多次收集才能补全。(目前主流的做法是推) 

总结

  jdk自带的观察者模式实现了主题对象和观察者之前的松耦合,定义了对象之间的一对多的关系,主题对象不需要知道观察者的细节,也不需要知道到底谁成为了观察者。jdk自带的观察者模式是使用继承的方式去实现,一定程度上违背的OO设计的原则:多用组合,少用继承,而且继承带来的问题必然是扩展的麻烦。Observable类其实是比较简单的,它的源码主要就是两个成员变量和几个方法,如果有必要的话,可以实现自己的Observable,希望各位小伙伴都能掌握松耦合的设计思想。

 

posted @ 2019-06-21 18:43  BlueAndWhite  阅读(169)  评论(0编辑  收藏  举报