一起去开心的购物吧——浅谈观察者模式

观察者模式

声明:本文为原创,如有转载请注明转载与原作者并提供原文链接,仅为学习交流,本人才识短浅,如有错误,敬请指正

嗨,大家好,我们又见面了,不知道上次的篮球比赛大家是不是还意犹未尽呢,没看到的同学可以前往https://www.cnblogs.com/MrJR/p/10441166.html观摩哦。

今天呢,我们来看另一个Java设计模式——观察者模式。

顾名思义,观察者模式,那肯定要有观察者,既然有了观察者,肯定就有被观察者,当然如果你说你就是喜欢发呆,啥都不观察,当我没说。

不能免俗,我们首先来看一下观察者模式的官方定义:

观察者模式:定义了对象之间的一对多依赖,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。

或许大家觉得这段话还蛮好理解的,毕竟没啥专业术语,当一个对象改变了,他的依赖者都会收到通知:喂,我被改变了,你们也要快快行动起来啦,问题的关键在于,如何保证通知的灵活性。

不是所有的观察者都想一直目不转睛盯着同一个东西,拜托,那会把人逼疯的,也会有人想一起加入观察的行列,有什么好东西呀,让我康康,如果我们把观察者与被观察者联系的过于紧密,意味着每次做出改变都是一个浩大的工程,我们要反复修改代码,实现对不同的观察者的通知,还记得我们的原则吗,对扩展开放,对修改关闭。

好啦,我们先把这些苦恼丢到一边,来看一下我们的新朋友,小王同学与小杨同学,她们可是一个十足的购物狂,每次逛街都能买好多的东西,最近呢,他们却在为购物而烦恼,这是为什么呢?我们来听听她们怎么说的。

 

杨:双十一马上就要到了,我在购物网站看中了一款BB霜和一款新手机。

王:真巧,我也看中了这两样东西,咱们一起买没准可以打折哟!

杨:买什么呀买,根本就抢不到,每次等我反应过来的时候,早就卖光了!!

王:这倒是个问题,我也经常抢不到自己想要的东西。

杨:要是商品刚上架,我们就能接受到通知就好了。

王:这样我们肯定就能抢到了。

 

作为一名程序员,我们是否应该立刻给两位可爱的女士伸出援手呢,当然是啦,而在这里,观察者模式就可以大显身手了。

我们可以看出,此处的观察者就是小杨与小王,而主题呢,我这里使用了主题二字,其实就是被观察者,这是观察者模式中的惯用说法,主题就是购物网站,而通知就是新商品的上架,最后观察者的改变便是小杨与小王的买买买。

我们首先定义一个观察者接口,这个接口定义了观察者在收到通知后应该执行的方法

public interface Person {

    void buy(String productionName);
}

 

此处当然就是买买买的方法啦,我们会传入一个商品名。

接下来我们定义主题接口

public interface ShoppingApp {

    void registerPerson(Person person);

    void removePerson(Person person);

    void notifyPerson();

}

主题接口就是购物APP,它有三个方法,相信通过方法名大家也能看出来它们的作用,分别是注册观察者,移除观察者与通知观察者。

然后,我们实现一个具体的购物网站。

public class TaoBao implements ShoppingApp {

    private LinkedList<Person> persons;
    private String productionName;

    public TaoBao(){
        persons = new LinkedList<>();
    }

    @Override
    public void registerPerson(Person person) {
        persons.add(person);
    }

    @Override
    public void removePerson(Person person) {
        if (persons.contains(person)){
            persons.remove(person);
        }else{
            System.out.println("错误操作,无法删除不存在的用户");
        }
    }

    @Override
    public void notifyPerson() {
        for(Person person : persons){
            person.buy(productionName);
        }
    }

    public void setProductionName(String productionName){
        this.productionName = productionName;
        notifyPerson();
    }
}

我们可以看到,在这个超迷你淘宝中,我们维护了一个链表,而这个链表储存的就是所有正在观察这个主题的观察者们,当然,我们初始化时把他置空。

我们实现注册观察者,直接将观察者对象添加进我们的观察者列表即可。

我们实现移除观察者,将观察者从链表中移除即可。

我们重点看一下通知方法的实现以及通知方法如何被调用,我们可以看到,为了通知每个观察者,我们遍历了所有的观察者们,然后调用了他们应对通知的方法,以表示他们已经接收到通知并做出了积极的回应,注意,我们一直使用的都是接口而不是具体类,我们只需要调用buy方法即可,根本不用去管到底是什么观察者,不管你是张三李四王五还是蜘蛛侠超人,反正我知道你肯定有buy这个方法,因为你实现了Person接口,这种针对接口编程而不是针对实现编程使我们的代码完全与具体类解耦,我们不需要去管到底是什么类在与我交互,毕竟如果你连这个接口都没实现,编译器都不会放过你的(笑)。

而在这个类里,我们何时通知观察者取决于我们的商品是否上架,即productionName是否被设置了值,当淘宝商品上架,我们就会调用通知方法,通知所有的观察者。

接下来,我们让小王同学和小杨同学现身。

public class MissW implements Person {

    @Override
    public void buy(String productionName) {
        System.out.println("王小玲同学:"+productionName + "终于开售了,还好提前关注了!");
    }
}
public class MissY implements Person {

    @Override
    public void buy(String productionName) {
        System.out.println("杨小青同学:我要的" + productionName + "终于有货了,我要赶紧抢!!");
    }
}

可以看出来,具体的观察者实现观察者接口后,只要按照自己的需求实现接口方法即可,在这里,我们只是简单的打印出一句话。

最后呢,当然就是我们的双十一登场啦,小杨同学与小王同学早就按捺不住激动的心情,要抢购了,双十一将检测我们的代码到底有没有起到作用。

public class Double11 {

    public static void main(String[] args) {

        TaoBao taoBao = new TaoBao();

        MissW wang = new MissW();
        MissY yang = new MissY();

        taoBao.registerPerson(wang);
        taoBao.registerPerson(yang);

        taoBao.setProductionName("雅诗兰黛高级BB霜");
        taoBao.setProductionName("华为Mate20 pro");
        
        taoBao.removePerson(wang);
        taoBao.setProductionName("悦诗风吟高级化妆礼盒");
    }
}

我们首先创建了超迷你淘宝对象作为具体主题,然后创建了小王同学与小杨同学作为具体观察者,接着小王与小杨就注册了淘宝,等着心仪的物品摆上货架,接收通知。

12点的钟声刚过,他们心仪的东西终于摆上了货架,我们来看运行结果,她们到底有没有接收到通知呢?

看来我们的小杨同学与小王同学都成功收到了淘宝发出的通知,在抢购了自己喜欢的东西之后,小王同学退出了淘宝,不再接收淘宝发出的通知,更不会再去买东西,而小杨同学仍然能接收到淘宝发出的通知而继续购物。

观察者模式可以在不影响原主题通知与观察者更新方法的基础上,新增或移除观察者,对扩展的开放,对修改的关闭的设计原则再一次展现了它强大的力量,同时我们还发现针对接口编程可以让我们六根清净,不必再被具体类所纠缠,这也是解耦的力量体现。

我们还要注意一件事,在购物的例子中,超迷你淘宝在商品上架后,主动给所有的观察者“推送”了消息,观察者则被动的接收消息,不管这个消息它是否需要(在我们的例子中,默认观察者收到的消息都是她们需要的),有可能观察者虽然关注了主题,但是只要主题的某些消息,那么这里就涉及到了另一种接收消息的方式——观察者主动”拉“消息,通过主题的getter方法,观察者可以主动去主题拉取自己需要的消息,根本应用场景的不同,两种方式各有千秋,大家可以自己动手实现一下试试。

好的,伴随着两位美丽的女士钱包空空,我的浅谈观察者模式也就先到这里了,我们下次再见哦。

posted @ 2019-02-28 00:40  JRUPER  阅读(705)  评论(3编辑  收藏  举报