设计模式之观察者模式

暗中观察

版权声明:本文为 冬夏 发表在公众号「Android从入门到精通」,可以随意转载,但请注明出处。

观察者模式(Observer)又称为发布-订阅(Publish-Subscribe)模式,它定义了对象之间一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

观察者模式是日常开发中使用最广的设计模式之一,有许多开源库也用到了观察者模式,比如说: Rxjava,EventBus 等等。

观察者模式UML

观察者模式主要有以下几个特点:
1. 观察者模式定义了对象之间一对多的关系
2. 观察者和被观察者之间用松耦合的方式
3. 观察者接收通知有两种方式,推和拉(推被认为更加正确)

那么怎么使用观察者模式呢?举一个例子

目前很火的微信公众号相信大家都不陌生,当我们关注了某一个公众号的之后,每当公众号有新文章的时候,我们都会自动接收到更新。但是公众号博主并不需要知道关注他公众号的每一个人究竟是谁。当我们想看这个公众号更多的文章时候,还可以点击「 历史文章 」进行查看。当我们取消对某一个公众号的关注之后,不管这个公众号以后有多少文章更新,我们都不会再收到了,除非我们再次关注这个公众号。

这个公众号的例子就是一个典型的观察者模式的应用实例。从这个例子里我们可以总结出观察者模式的使用流程。

  1. 注册(当我们关注了某个公众号的时候,实际上就是完成了注册的流程,我们告诉了该公众号「 我关注了你,以后你有新文章记得推送给我 」。)
  2. 通知(当我们接收到该公众号的新文章的时候,实际上就是完成了通知的流程,公众号告诉了我们「 我新发表了一篇文章,记得查收哦 」。)
  3. 拉取(当我们想查看该公众号更多的文章,点击了「历史文章」或其他按钮的时候,实际上就是完成了拉取的过程,我们告诉了该公众号「 我想看你其他的文章,你把链接发给我一下 」。)
  4. 解注册(当我们取消对某个公众号的关注的时候,实际上就是完成了解注册的流程,我们告诉了该公众号「 我不想再看你写的文章了,你以后都别推送给我了 」。)

接下来,我们通过一个简单的例子实现一下观察者模式

public interface Observer {

void update(Observerable observerable, Object obj);
}

public interface Observerable {

    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();

}

public class Publisher implements Observerable {

    private String publisherName;
    private List<Observer> observers = new ArrayList<>();
    private List<String> articles = new ArrayList<>();
    private String latestArticle = null;

    public Publisher(@NotNull String name){
        publisherName = name;
    }

    public String getPublisherName() {
        return publisherName;
    }

    @Override
    public void addObserver(Observer observer) {
        if (!observers.contains(observer)){
            observers.add(observer);
        }
    }

    @Override
    public void removeObserver(Observer observer) {
        if (observers.contains(observer)){
            observers.remove(observer);
        }
    }


    @Override
    public void notifyObservers() {
        for (Observer observer : observers){
            observer.update(this,latestArticle);
        }
    }

    public void addNewArticle(String articleName){
        articles.add(articleName);
        latestArticle = articleName;
        notifyObservers();
    }

    public List<String> getArticleList(){
        return articles;
    }

}


public class Reader implements Observer {
    private String readerName;

    List<Publisher> publishers = new ArrayList<>();


    public Reader(@NotNull String name){
        readerName = name;
    }

    public void follow(Publisher publisher){
        if (!publishers.contains(publisher)){
            publishers.add(publisher);
            publisher.addObserver(this);

            System.out.println("读者: " + readerName +
                    " 关注公众号:" + publisher.getPublisherName());
        }
    }

    public void unfollow(Publisher publisher){
        if (publishers.contains(publisher)){
            publishers.remove(publisher);
            publisher.removeObserver(this);
            System.out.println("读者: " + readerName +
                    " 取消关注公众号:" + publisher.getPublisherName());
        }
    }

    @Override
    public void update(Observerable observerable, Object obj) {
        System.out.println("读者: " + readerName
                + " 接收到公众号: " + ((Publisher)observerable).getPublisherName()
                + "的新文章: " + (String)obj);
    }

    public void getAllArticleByPublisher(Publisher publisher){
        if (publishers.contains(publisher)){
            publisher.getArticleList();
            System.out.println("读者: " + readerName
                    + " 获取公众号: " + publisher.getPublisherName()
                    + "的所有文章");
        }else {
            System.out.println("没有关注该公众号");
        }
    }

}

public class Test {
    public static void main(String[] args){
        Publisher publisherA = new Publisher("公众号1");
        Publisher publisherB = new Publisher("公众号2");
        Reader readerA = new Reader("读者1");
        Reader readerB = new Reader("读者2");

        readerA.follow(publisherA);
        publisherA.addNewArticle("设计模式之观察者模式");

        readerB.follow(publisherA);
        publisherA.addNewArticle("设计模式之单例模式");

        publisherB.addNewArticle("设计模式之策略模式");

        readerA.follow(publisherB);

        readerA.unfollow(publisherA);
        readerA.getAllArticleByPublisher(publisherA);
        readerA.getAllArticleByPublisher(publisherB);

    }
}

通过上面的代码,我们就可以模拟出公众号和读者的关注,推送,获取,取消关注四个操作。

上面的代码执行结果为:

读者: 读者1 关注公众号:公众号1
读者: 读者1 接收到公众号: 公众号1的新文章: 设计模式之观察者模式
读者: 读者2 关注公众号:公众号1
读者: 读者1 接收到公众号: 公众号1的新文章: 设计模式之单例模式
读者: 读者2 接收到公众号: 公众号1的新文章: 设计模式之单例模式
读者: 读者1 关注公众号:公众号2
读者: 读者1 取消关注公众号:公众号1
没有关注该公众号
读者: 读者1 获取公众号: 公众号2的所有文章

那么什么时候就应该使用观察者模式呢?

  1. 当一个模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  2. 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
  3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

最后提一点,其实 Java 源码中的 「 java.util.Observer 」和 「 java.util.Observable 」 两个类就帮我们实现了观察者模式,但是有一点不同的是,「 java.util.Observable 」是类而不是接口,而 Java 的单继承机制就导致我们不能在继承「 java.util.Observable 」的时候同时又继承别的类。

欢迎关注我的个人公众号,一起学习Android、Java、设计模式等技术!
Android从入门到精通

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值