设计模式——观察者模式

设计模式——观察者模式

观察者模式,顾名思义,就是由发布者和观察者组成的一个一对多的关系。观察者依赖发布者。如果发布者有了动作,它的观察者们都能察觉到。

1.情景举例

今天,老板突然有个想法,他想做一个新闻推送机。如果有了新的新闻,新闻推送机将为每个登录的用户推送这条新闻。

2.通往观察者模式的道路

新闻推送机有一个,用户有多个,构成一对多的关系。这个问题用观察模式去做再适合不过了。

先来做一些基础准备吧。

首先,要有个用户类

public class User {
    
    String name;

    public User(String name) {
        this.name = name;
    }

    public void displayMyName() {
        System.out.println("My name is " + name);
    }
}

在整个继承层次中User类可能会被多次继承以生成各式各样的子类,这里就不再列举。

接着,再来个新闻推送机类

public class NewsPusher {
    
    String news;
    
    //更新新闻时调用此方法
    public void setLatestNews(String news) {
        this.news = news;
    }

}

3.使用观察者模式

首先,我们要建立这个一对多的关系。这时问题来了

Q:怎么在一个新闻推送机内获得运行时动态变化的多个登录用户的实例呢?

A:可以建立一个观察者的集合,把所有的登录用户添加进去。

Q:这个方法很棒,但是如果我的List是User类型的话,我就必须为User基类添加一个显示新闻的方法啊,这不合逻辑啊。而且以后说不定会有非User继承体系的观察者也需要推送新闻呢?

A:修改User类是违背原则的事情,这里为了统一所有接受新闻推送的对象(观察者),需要新建一个Observer的接口,这个接口只需要定义一个显示新闻的方法即可。让想要获得新闻推送的对象实现这个接口即可,最后让新闻发布机的List的类型是接口类型,这样所有想要得到最新新闻的对象都可以如愿以偿了。

Q:太棒了,但是总会有用户不想要新闻推送,绝对不能在用户登录时就自动加入到新闻推送的列表的。我想要拥有用户动态订阅新闻推送和取消新闻推送的方法,但是这些方法定义到新闻推送机内部也不好,毕竟不是每个新闻推送机都想推送新闻。

A:那就给再新建一个接口Suject,接口中定义用户订阅/取消推送,推送新闻的方法。

Subject接口

public interface Subject {

    //增加观察者
    void addObserver(Observer observer);

    //删除观察者
    void deleteObserver(Observer observer);

    //新闻推送
    void pushNews();
}

Observer接口

public interface Observer {

    //显示推送的新闻
    void displayNews(Subject pusher, String news);
}

关于在displayNews中加入了一个Subject类型参数的原因是:在实现Observer接口的类中可以增加一个Subject类型的变量,在推送消息时动态赋值,这样即使在项目取消推送,可以很方便的通过这Subject来调用相应方法。也可以通过这个引用二次获取最新新闻。并且由于所有的推送者都实现了Subject接口,这个引用可以兼容所有的推送者。

通过Observer和Subject这两个接口,一对多的关系就建立起来了,Subject只针对Observer进行操作,Observer只接受Subject类型的消息。像这样独立封装功能动作,是设计模式的一个基本思想,它可以把对象和算法解耦,从而让整个体系获得更好的扩展性和弹性。

新闻推送机代码

public class NewsPusher implements Subject{

    String news;
    ArrayList<Observer> list = new ArrayList<>();

    //更新新闻时调用此方法
    public void setLatestNews(String news) {
        this.news = news;
        pushNews();
    }

    @Override
    public void addObserver(Observer observer) {
        list.add(observer);
    }

    @Override
    public void deleteObserver(Observer observer) {
        list.remove(observer);
    }
    @Override
    public void pushNews() {
        //给所有观察者推送消息
        for(int i = 0; i < list.size(); i++) {
            list.get(i).displayNews(this,news);
        }
    }
}

接受推送的对象代码

public class User implements Observer{

    Subject pusher;
    String name;

    public User(String name) {
        this.name = name;
    }

    public void displayMyName() {
        System.out.println("My name is " + name);
    }

    @Override
    public void displayNews(Subject pusher, String news) {
        //获得推送者的引用
        this.pusher = pusher;
        System.out.println(name + " gets the latest news : " + news);
    }
}

测试

public class MainTest {

    public static void main(String[] args) {
        NewsPusher newsPusher = new NewsPusher();
        //观察者订阅推送
        newsPusher.addObserver(new User("小李"));
        newsPusher.addObserver(new User("小王"));
        newsPusher.addObserver(new User("小张"));
        //更新新闻
        newsPusher.setLatestNews("天气真好啊");
        newsPusher.setLatestNews("今天食堂免费就餐");
        newsPusher.setLatestNews("明天有大雨");
    }
}

4.观察者模式小结

观察者模式的大体实现步骤就是

1.编写Observer和Subject接口,实现一对多的关系

2.给发布消息的类实现Subject接口,给接受消息的类实现Observer接口

观察者模式是运用特别广泛的一个设计模式,在JDK中,Swing包中很多组件的事件监听功能就是通过观察者模式实现的。

观察者模式的实现方式也不只这一种,并且JDK也自带了实现观察者模式的工具包,有兴趣的话大家可以了解一下。

在项目开发中,只要遇到了拥有一对多关系,都可以想一下是否可以套用观察者模式。但是一定要把“一”和“多”这一个关系抽象出来(做成类似Subject和Observer接口),这样可以减小耦合度,使项目获得更好的扩展性和伸缩性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值