【设计模式】观察者模式

简介:  前面学习了策略模式,接着学习观察者模式,观察者模式是一个很常用的模式,如订阅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,谢谢各位园友的观看~

目录
相关文章
|
4月前
|
设计模式 PHP
php设计模式--观察者模式(4.1)面向过程完成页面内容切换
php设计模式--观察者模式(4.1)面向过程完成页面内容切换
30 0
|
5天前
|
设计模式 Java 关系型数据库
设计模式——观察者模式
观察者模式介绍、观察者模式优化天气预报案例、JDK 的Observable类和Observer类
设计模式——观察者模式
|
4月前
|
设计模式 监控 Java
设计模式 - 观察者模式(Observer):Java中的战术与策略
【4月更文挑战第7天】观察者模式是构建可维护、可扩展系统的关键,它在Java中通过`Observable`和`Observer`实现对象间一对多的依赖关系,常用于事件处理、数据绑定和同步。该模式支持事件驱动架构、数据同步和实时系统,但需注意避免循环依赖、控制通知粒度,并关注性能和内存泄漏问题。通过明确角色、使用抽象和管理观察者注册,可最大化其效果。
98 2
|
1月前
|
设计模式 存储 前端开发
【十四】设计模式~~~行为型模式~~~观察者模式(Java)
文章详细介绍了观察者模式(Observer Pattern),这是一种对象行为型模式,用于建立对象之间的一对多依赖关系。当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。文中通过交通信号灯与汽车的案例以及多人联机对战游戏的设计方案,阐述了观察者模式的动机和应用场景。接着,文章介绍了观察者模式的结构、角色、优点、缺点以及适用情况,并通过代码示例展示了如何在Java中实现观察者模式。此外,还探讨了观察者模式在MVC架构中的应用以及Java中对观察者模式的支持。
【十四】设计模式~~~行为型模式~~~观察者模式(Java)
|
1月前
|
设计模式 安全 Go
[设计模式]行为型模式-观察者模式
[设计模式]行为型模式-观察者模式
|
1月前
|
设计模式 Go
go 设计模式之观察者模式
go 设计模式之观察者模式
|
2月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
60 1
|
2月前
|
设计模式 缓存
iLogtail设计模式问题之观察者模式在iLogtail中是如何应用的
iLogtail设计模式问题之观察者模式在iLogtail中是如何应用的
|
3月前
|
设计模式 消息中间件 存储
跟着GPT学设计模式之观察者模式
观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,其依赖对象都能够收到通知并自动更新。一般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。
26 1
|
3月前
|
设计模式 存储 Java
Java设计模式之观察者模式详解
Java设计模式之观察者模式详解