【设计模式】观察者模式

简介:  前面学习了策略模式,接着学习观察者模式,观察者模式是一个很常用的模式,如订阅RSS这个功能就适合使用观察者模式来实现,园友订阅了博客园文章后,当博客园的文章有更新时,会收到相应的通知,这就是观察者模式的应用,并且JDK中都内置了对观察者模式的支持,下面来学习观察者模式。

一、前言


  前面学习了策略模式,接着学习观察者模式,观察者模式是一个很常用的模式,如订阅RSS这个功能就适合使用观察者模式来实现,园友订阅了博客园文章后,当博客园的文章有更新时,会收到相应的通知,这就是观察者模式的应用,并且JDK中都内置了对观察者模式的支持,下面来学习观察者模式。


二、观察者模式定义


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


  定义中的一通常称为主题,多称为观察者,当主题发生变化时,观察者会收到相应的变化,下面通过示例来演示观察者模式。


三、示例


  若有这样的一个场景,当园友订阅博客园文章后,博客园文章更新后,程序员需要收到更新的文章。这时,使用观察者模式最合适不过了。下面是类图

download.png

说明:Subject是主题接口,包含了三个方法,CNBlog是具体的主题,表示博客园,Oberser是观察者接口,包含了update方法,在主题发生变化时,update方法会被调用,Coder是具体的观察者,表示程序员。


  3.1 v1.0


  根据类图,代码如下


  Subject

package com.hust.grid.leesf.observer;
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

 Observer

package com.hust.grid.leesf.observer;
public interface Observer {
    void update(String message);
}

 CNBlog  

package com.hust.grid.leesf.observer;
import java.util.ArrayList;
import java.util.List;
public class CNBlog implements Subject {
    private List<Observer> observers;
    private String message;
    public CNBlog() {
         observers = new ArrayList<Observer>();
    }
    @Override 
    public void registerObserver(Observer observer) {
        observers.add(observer);
    } 
    @Override
    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if (index >= 0) {
            observers.remove(index);
        }
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
    /**
     * 模拟博客园的文章更新了
     * @param message
     */
    public void setMessage(String message) {
        this.message = message;
        // 有更新
        messageChanged();
    }
    private void messageChanged() {
        // 通知观察者
        notifyObservers();
    }
}

 Coder  

package com.hust.grid.leesf.observer;
public class Coder implements Observer {
    private String name;
    public Coder(String name) {
        this.name = name;
    }
    @Override
    public void update(String message) {
        System.out.println("I am " + name + ", received updated message from subject is [" + message + "]");
    }
}

Main(用于测试)

package com.hust.grid.leesf.observer;
/**
 * @since 2016/6/1
 * @author LEESF
 *
 */
public class Main {
    public static void main(String[] args) {
        // 新生主题
        CNBlog cnBlog = new CNBlog();
        // 新生程序员
        Observer leesf = new Coder("leesf");
        // 向主题注册
        cnBlog.registerObserver(leesf);
        // 新生程序员
        Observer lee = new Coder("lee");
        // 向主题注册
        cnBlog.registerObserver(lee);
        // 模拟主题发生变化
        cnBlog.setMessage("leesf发布了一篇新文章");
        System.out.println("----------------------------------------");
        // 移除观察者
        cnBlog.removeObserver(lee);
        // 模拟主题发生变化
        cnBlog.setMessage("leesf又发布了一篇新文章");
    }
}

 运行结果

I am leesf, received updated message from subject is [leesf发布了一篇新文章]
I am lee, received updated message from subject is [leesf发布了一篇新文章]
----------------------------------------
I am leesf, received updated message from subject is [leesf又发布了一篇新文章]

 说明:首先,leesf与lee向CNBlog主题进行了注册,成为观察者,之后,CNBlog的信息发生变化,可以看到,此时,leesf与lee都收到了通知;之后,从主题中移除观察者lee,CNBlog的信息再次发生变化时,只有leesf收到了信息,而lee则不会收到信息。


  这样的设计会使得系统极具扩展性,可以方便的添加其他主题或者观察者而不会影响之前的代码。如,可以添加一个CSDN主题、今日头条主题等,这些主题只需要实现Subject接口即可,同时,也可以添加其他类型观察者,如设计师、科学家等,这些观察者只需要实现Observer接口即可。类图如下图所示


download.png

 说明:Coder向CNBlog、CSDN主题进行注册,成为它们观察者;Designer向TouTiao、CSDN主题进行注册,成为它们的观察者;Scientist想TouTiao注册,成为它的观察者。


  3.2 v2.0


  根据类图,代码如下


  CSDN 

package com.hust.grid.leesf.observer;
import java.util.ArrayList;
import java.util.List;
public class CSDN implements Subject {
    private List<Observer> observers;
    private String message;
    public CSDN() {
        observers = new ArrayList<Observer>();
    }
    @Override 
    public void registerObserver(Observer observer) {
        observers.add(observer);
    } 
    @Override
    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if (index >= 0) {
            observers.remove(index);
        }
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
    /**
     * 模拟CSDN的文章更新了
     * @param message
     */
    public void setMessage(String message) {
        this.message = message;
        // 有更新
        messageChanged();
    }
    private void messageChanged() {
        // 通知观察者
        notifyObservers();
    }    
}

TouTiao

package com.hust.grid.leesf.observer;
import java.util.ArrayList;
import java.util.List;
public class TouTiao implements Subject {
    private List<Observer> observers;
    private String message;
    public TouTiao() {
        observers = new ArrayList<Observer>();
    }
    @Override 
    public void registerObserver(Observer observer) {
        observers.add(observer);
    } 
    @Override
    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if (index >= 0) {
            observers.remove(index);
        }
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
    /**
     * 模拟头条的的新闻更新了
     * @param message
     */
    public void setMessage(String message) {
        this.message = message;
        // 有更新
        messageChanged();
    }
    private void messageChanged() {
        // 通知观察者
        notifyObservers();
    }    
}

Designer 

package com.hust.grid.leesf.observer;
public class Designer implements Observer {
    private String name;
    public Designer(String name) {
        this.name = name;
    }
    @Override
    public void update(String message) {
        System.out.println("I am " + name + ", received updated message from subject is [" + message + "]");
    }
}

Scientist

package com.hust.grid.leesf.observer;
public class Scientist implements Observer {
    private String name;
    public Scientist(String name) {
        this.name = name;
    }
    @Override
    public void update(String message) {
        System.out.println("I am " + name + ", received updated message from subject is [" + message + "]");
    }
}

Main(用作测试)

package com.hust.grid.leesf.observer;
/**
 * @since 2016/6/1
 * @author LEESF
 *
 */
public class Main {
    public static void main(String[] args) {
        // 新生主题
        CNBlog cnBlog = new CNBlog();
        CSDN csdn = new CSDN();
        TouTiao touTiao = new TouTiao();
        // 新生程序员
        Observer leesf = new Coder("leesf");
        // 向CNBlog主题注册
        cnBlog.registerObserver(leesf);
        // 向CSDN主题注册
        csdn.registerObserver(leesf);
        // 新生设计师
        Observer dyd = new Coder("dyd");
        // 向CSDN主题注册
        csdn.registerObserver(dyd);
        // 向头条主题注册
        touTiao.registerObserver(dyd);
        // 新生科学家
        Observer ld = new Scientist("ld");
        // 向头条主题注册
        touTiao.registerObserver(ld);
        // 模拟主题发生变化
        cnBlog.setMessage("leesf在博客园上发布了一篇新文章");
        System.out.println("----------------------------------------");
        // 模拟主题发生变化
        csdn.setMessage("leesf在CSDN上发布了一篇新文章");
        System.out.println("----------------------------------------");
        // 模拟主题发生变化
        touTiao.setMessage("头条更新了新闻");
    }
}

运行结果

I am leesf, received updated message from subject is [leesf在博客园上发布了一篇新文章]
----------------------------------------
I am leesf, received updated message from subject is [leesf在CSDN上发布了一篇新文章]
I am dyd, received updated message from subject is [leesf在CSDN上发布了一篇新文章]
----------------------------------------
I am dyd, received updated message from subject is [头条更新了新闻]
I am ld, received updated message from subject is [头条更新了新闻]

说明:可以看到,不同的主题更新,会通知向该主题注册的观察者。并且新增的主题和观察者并没有修改原来的Subject、Observer代码,使得其具有很好的可维护性。


  有了观察者的概念,再看JDK里面的观察者模式就会非常简单,有兴趣的读者可以自行查阅。笔者不再累赘。


四、总结


  掌握了观察者模式后,在进行系统设计的时候,若可以使用观察者模式,则尽管去使用观察者模式吧,它会让你的系统更加灵活和易于扩展。所有源代码已经上传至github,欢迎fork,谢谢各位园友的观看~

目录
相关文章
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
2月前
|
设计模式 传感器
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
44 0
|
14天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
32 1
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
27 3
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
34 9
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
34 2
|
2月前
|
设计模式 监控 UED
设计模式之观察者模式
【10月更文挑战第12天】 观察者模式是一种行为型设计模式,定义了一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动更新。主要由主题(被观察者)和观察者组成,实现对象间的松耦合,广泛应用于用户界面、事件驱动系统和数据监控等领域。
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
本教程详细讲解Kotlin语法,适合深入学习。对于快速掌握Kotlin,推荐“简洁”系列教程。本文特别介绍了观察者模式,包括使用Java API和Kotlin委托属性(如Delegates.observable)实现的方法,旨在帮助开发者更高效地实现和优化观察者模式的应用。
38 3
|
3月前
|
设计模式 Java 关系型数据库
设计模式——观察者模式
观察者模式介绍、观察者模式优化天气预报案例、JDK 的Observable类和Observer类
设计模式——观察者模式
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
34 0