【设计模式】观察者模式

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

目录
相关文章
|
设计模式 监控 Java
Kotlin - 改良设计模式 - 观察者模式
Kotlin - 改良设计模式 - 观察者模式
299 3
|
11月前
|
设计模式 缓存 Java
Java设计模式(二):观察者模式与装饰器模式
本文深入讲解观察者模式与装饰器模式的核心概念及实现方式,涵盖从基础理论到实战应用的全面内容。观察者模式实现对象间松耦合通信,适用于事件通知机制;装饰器模式通过组合方式动态扩展对象功能,避免子类爆炸。文章通过Java示例展示两者在GUI、IO流、Web中间件等场景的应用,并提供常见陷阱与面试高频问题解析,助你写出灵活、可维护的代码。
|
9月前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
659 8
|
设计模式 存储 供应链
前端必须掌握的设计模式——观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,实现了一种订阅机制。它包含两个角色:**观察者**(订阅消息、接收通知并执行操作)和**被观察者**(维护观察者列表、发送通知)。两者通过一对多的关系实现解耦,当被观察者状态改变时,会通知所有订阅的观察者。例如,商店老板作为被观察者,记录客户的需求并在商品到货时通知他们。前端应用中,如DOM事件注册、MutationObserver等也体现了这一模式。
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
设计模式 传感器
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
315 0
|
设计模式 消息中间件 存储
【设计模式】【行为型模式】观察者模式(Observer)
一、入门 什么是观察者模式? 观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。
544 9
|
设计模式 消息中间件 存储
设计模式:观察者模式
观察者模式属于行为型设计模式,用于建立对象间的一对多依赖关系。当主题(Subject)状态变化时,所有依赖的观察者(Observer)会自动收到通知并更新。
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
369 6

热门文章

最新文章