Java 设计模式 -- 观察者模式

学校里有个十分可爱的女孩子,很多男孩都纷纷加入了她的粉丝行列,大家争先恐后的去搜集她的信息。这个时候女孩的室友,同学都开始向她抱怨,她也深感愧疚,感觉麻烦了周围的朋友。于是,她决定公开自己的状态,前提是不再去麻烦她身边的人。开始,她公开自己每天吃饭和学习的状态,只要她的粉丝在她这里进行注册,就可以不费吹灰之力的收到自己的动态信息,这对于粉丝而言简直是个天大的好消息…这个时候一个程序员路过,看到了这个现象,灵光一闪,这是观察者模式。首先,将女孩抽象成一个类,她的行为我们也可以写成方法,于是有了下面这两个类。

public interface Girl {
    public void addFans(Fans fans);

    public void removeFnas(Fans fans);

    public void notifyFans();
}

public class LovelyGirl implements Girl {
    private String eatState = "Inexact";
    private String studyState = "Inexact";
    private ArrayList<Fans> fanses;

    public LovelyGirl() {
        fanses = new ArrayList<>();
    }

    @Override
    public void addFans(Fans fans) {
        fanses.add(fans);
    }

    @Override
    public void removeFnas(Fans fans) {
        int i = fanses.indexOf(fans);
        if (i >= 0) {
            fanses.remove(i);
        }
    }

    @Override
    public void notifyFans() {
        for (int i = 0; i < fanses.size(); i++) {
            Fans fans = fanses.get(i);
            fans.update(eatState, studyState);
        }
    }

    public void setEatState(String eatState) {
        this.eatState = eatState;
        notifyFans();
    }

    public void setStudyState(String studyState) {
        this.studyState = studyState;
        notifyFans();
    }
}

这里,将女孩写成了一个接口。毕竟,人总会见异思迁的嘛,万一学校里来了个很漂亮的女孩子呢?那恐怕就要多出一个 BeautyGirl 类了。讲完了女孩,我们也得讲讲那些粉丝吧,粉丝有很多,他们的目的也只有一个 ——获取自己心仪女孩的最新信息。那好吧,为了让你们和女神保持一致,也为你们写一个接口吧。

public interface Fans {
    public void update(String eatState, String studyState);
}

有了接口之后,众多的粉丝们就可以实现这个接口,去获得最新信息了。比如说粉丝甲和粉丝乙——

public class FansOne implements Fans {

    @Override
    public void update(String eatState, String studyState) {
        System.out.println("I am fans one : " + eatState + ", " + studyState);
    }
}
public class FansTwo implements Fans {

    @Override
    public void update(String eatState, String studyState) {
        System.out.println("I am fans two : " + eatState + ", " + studyState);
    }
}

好了,所有准备工作已经完成了,不过这个时候已经中午了,女孩说了,我要开始吃饭了,比如像下面这样

public class Client {
    public static void main(String[] args) {
        LovelyGirl girl = new LovelyGirl();

        FansOne fansOne = new FansOne();
        girl.addFans(fansOne);

        FansTwo fansTwo = new FansTwo();
        girl.addFans(fansTwo);

        girl.setEatState("I am eating");
    }
}

打印结果如下

I am fans one : I am eating, Inexact
I am fans two : I am eating, Inexact

其实,上面这么一个例子就是我们常说的观察者模式。观察者模式定义了对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖者都会收到通知并且自动更新。生活中很多地方用到这种模式,比如说天气预报订阅系统,报纸订阅系统等。

上面这个例子还有可以修改之处,因为我们只写了推送功能,如果粉丝们想主动获取信息呢?如果有的粉丝对你的学习状态不感兴趣并且表示再也不想收到关于学习的信息推送了。那么该怎么进行改进呢?正好借这个机会,我们来看看 Java 为我们内置的观察者模式。Java 为我们提供了 Observer 接口和 Observable 类,下面我们来介绍一下如何使用。

  • 如何把对象变成观察者 ?
    实现观察者接口,然后调用 Observable 对象的 addObserver() 方法。不在想当观察者对象的时候,调用 deleteObserver() 方法就可以了。

  • 可观察者如何送出通知 ?
    首先,需要继承 java.util.Observable 类产生可观察者类,然后需要两个步骤。

    1. 先调用 setChanged() 方法,标记状态已经改变的事实。
    2. 然后调用两种 notifyObservers() 方法中的一个 : notifyObservers() 或者notifyObservers(Object arg)
  • 观察者如何接受通知?
    观察者实现了更新的方法,但是方法的签名不太一样 : update(Observable o, Object arg)。 这个时候就可以实现两种不同的效果。如果我们将 Object 属性不指定,也就是只传递 Observable 对象的值,这个时候就是默认不推送给观察者任何信息,不过观察者可以通过被观察者提供的 get 方法主动获取消息(这里也暗示了一个信息,就是我们的观察者内部需要获得被观察者的引用)。如果这里我们指定了 Object 的对象,那么被观察者会将信息推送给观察者。

注意哦,以上我们提到的 update() 方法中的 Object 参数和被观察者中notifyObservers(Object o) 中的 Object 是对应的。

利用以上介绍的信息,去改写以上的代码。

public class LovelyGirl extends Observable {
    private String eatState = "Inexact";
    private String studyState = "Inexact";

    public void setEatState(String eatState) {
        this.eatState = eatState;

    }

    public void setStudyState(String studyState) {
        this.studyState = studyState;
    }

    public String getEatState() {
        return eatState;
    }

    public String getStudyState() {
        return studyState;
    }

    public void stateChanged() {
        setChanged();
        notifyObservers();
    }
}

可见,在这里我们使用了无参数的 notifyObservers() 方法,这也就意味着,我们采用了不主动推送的方式。还有这里的 setChanged(),是 Observable 类中实现的一个方法,这个方法的作用是标记状态已经改变的事实,只有调用了这个函数,被观察者才会将最新的状态通知观察者。

public class FansOne implements Observer {

    private Observable observable;

    public FansOne(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof LovelyGirl) {
            LovelyGirl girl = (LovelyGirl) o;
            System.out.println("eatState : " + girl.getEatState() +
                    " studyState : " + girl.getStudyState());
        }
    }
}

可见,这里我们就将 addObserver() 方法写到了这里,因为我们既然在观察者中引用了被观察者对象,也就没有必要将添加的方法放入主函数了。这个时候再看看主函数的代码以及输出结果

public class Client {
    public static void main(String[] args) {
        LovelyGirl girl = new LovelyGirl();
        FansOne fansOne = new FansOne(girl);

        girl.setEatState("I am eating...");
    }
}


eatState : I am eating... studyState : Inexact

可见,利用了Java 内置的观察者模式之后,我们自己动手写的代码量就就减少了许多,而且逻辑也更加清晰了。不过我感觉 Java 内部将 Observable 设置为一个类还是有缺点的,因为Java 并不允许多重继承,这就限制了 Observable 的复用能力~

    原文作者:ghwaphon
    原文地址: https://www.jianshu.com/p/0073e091b266
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞