Java观察者模式(Observer)

简介: Java观察者模式(Observer)

文章目录


观察者模式

一、概述

1. 使用场景

2. UML类图

3. 核心角色

二、手动实现观察者模式

1.定义抽象被观察者角色

2.定义抽象观察者角色

3.定义具体被观察者角色

4.定义具体观察者角色

5.测试

三、Java内置观察者模式实现

1.定义具体被观察者

2.定义具体观察者

3.测试

四、开发中的常用场景:


 观察者模式java GOF23种设计模式中的一种。在最近介绍的Redis和ActiveMQ中都涉及到了观察者模式,所以我们在本文详细介绍下此模式:

观察者模式


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


一、概述


1. 使用场景


广播机制场景

20190216231601318.png

聊天室程序的创建。服务器创建好后,A,B,C三个客户端连上来公开聊天。A向服务器发送数据,服务器端聊天数据改变。我们希望将这些聊天数据分别发给他在线的客户。也就是说,每个客户端需要更新服务器端得数据。

网站上,很多人订阅了”java主题”的新闻。当有这个主题新闻时,就会将这些新闻发给所有订阅的人。

大家一起玩CS游戏时,服务器需要将每个人的方位变化发给所有的客户

 上面这些场景,我们都可以使用观察者模式来处理。我们可以把多个订阅者、客户称之为观察者; 需要同步给多个订阅者的数据封装到对象中,称之为目标.


2. UML类图

20190216232041919.png

3. 核心角色


抽象被观察者角色:

 也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。

抽象观察者角色:

 为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

具体被观察者角色:

 也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。

具体观察者角色:

 实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。


二、手动实现观察者模式


1.定义抽象被观察者角色

package com.dpb.observer;
import java.util.ArrayList;
import java.util.List;
/**
 * 观察者模式:目标对象模板
 * @author dengp
 *
 */
public interface Subject<T> {
  // 存储订阅者
  List<Observer> list = new ArrayList<>();
  // 注册订阅者
  public void registerObserver(T obs);
  // 移除订阅者
  public void removeObserver(T obs);
  //通知所有的观察者更新状态
  public void notifyAllObservers();
}

2.定义抽象观察者角色

/**
 * 观察者模式:定义观察者 
 * @author dengp
 *
 */
public interface Observer {
  void  update(Subject subject);
}

3.定义具体被观察者角色

/**
 * 观察者模式:目标对象(主体对象 topic)
 * @author dengp
 *
 */
public class ConcreteSubject implements Subject<Observer> {
  private int state;
  public int getState() {
    return state;
  }
  public void setState(int state) {
    this.state = state;
    //主题对象(目标对象)值发生了变化,请通知所有的观察者
    this.notifyAllObservers();
  }
  @Override
  public void notifyAllObservers() {
    for (Observer obs : list) {
      // 更新每一个观察者中的信息
      obs.update(this);
    }
  }
  @Override
  public void registerObserver(Observer obs) {
    // TODO Auto-generated method stub
    list.add(obs);
  }
  @Override
  public void removeObserver(Observer obs) {
    // TODO Auto-generated method stub
    list.remove(obs);
  }
}

4.定义具体观察者角色

package com.dpb.observer;
/**
 * 观察者模式:观察者 实现
 * @author dengp
 *
 */
public class ObserverA implements Observer {
  //myState需要跟目标对象的state值保持一致!
  private int myState;   
  /**
   * 更新为和目标对象的值一致
   */
  @Override
  public void update(Subject subject) {
    myState = ((ConcreteSubject)subject).getState();
  }
  public int getMyState() {
    return myState;
  }
  public void setMyState(int myState) {
    this.myState = myState;
  }
}

5.测试

package com.dpb.observer;
public class Client {
  public static void main(String[] args) {
    //目标对象
    ConcreteSubject subject = new ConcreteSubject();
    //创建多个观察者
    ObserverA  obs1 = new ObserverA();
    ObserverA  obs2 = new ObserverA();
    ObserverA  obs3 = new ObserverA();
    //将这三个观察者添加到subject对象的观察者队伍中
    subject.registerObserver(obs1);
    subject.registerObserver(obs2);
    subject.registerObserver(obs3);
    //改变subject的状态
    subject.setState(3000);
    System.out.println("########################");
    //我们看看,观察者的状态是不是也发生了变化
    System.out.println(obs1.getMyState());
    System.out.println(obs2.getMyState());
    System.out.println(obs3.getMyState());
    //改变subject的状态
    subject.setState(30);
    System.out.println("########################");
    //我们看看,观察者的状态是不是也发生了变化
    System.out.println(obs1.getMyState());
    System.out.println(obs2.getMyState());
    System.out.println(obs3.getMyState());
    //改变subject的状态
    subject.setState(99);
    System.out.println("########################");
    //我们看看,观察者的状态是不是也发生了变化
    System.out.println(obs1.getMyState());
    System.out.println(obs2.getMyState());
    System.out.println(obs3.getMyState());
  }
}

20190216233325181.png

三、Java内置观察者模式实现


 在java.util包中包含有基本的Observer接口和Observable抽象类.功能上和Subject接口和Observer接口类似.不过在使用上,就方便多了,因为许多功能比如说注册,删除,通知观察者的那些功能已经内置好了.


1.定义具体被观察者

package com.dpb.observer2;
import java.util.Observable;
/**
 * 目标对象
 * 继承 Observable
 * @author dengp
 *
 */
public class ConcreteSubject extends Observable {
  private int state; 
  public void set(int s){
    state = s;  //目标对象的状态发生了改变
    setChanged();  //表示目标对象已经做了更改
    notifyObservers(state);  //通知所有的观察者
  }
  public int getState() {
    return state;
  }
  public void setState(int state) {
    this.state = state;
  }
}

观察者只需要继承Observable父类。发送消息的方式执行如下两行代码即可

setChanged();  //表示目标对象已经做了更改
notifyObservers(state);  //通知所有的观察者

Observable源码对应的是:

20190216234306676.png20190216234428190.png

2.定义具体观察者

package com.dpb.observer2;
import java.util.Observable;
import java.util.Observer;
/**
 * 观察者模式:观察者(消息订阅者)
 * 实现Observer接口
 * @author dengp
 *
 */
public class ObserverA implements Observer {
  private int myState;
  @Override
  public void update(Observable o, Object arg) {
    myState = ((ConcreteSubject)o).getState();
  }
  public int getMyState() {
    return myState;
  }
  public void setMyState(int myState) {
    this.myState = myState;
  }
}

观察者也就是订阅者只需要实现Observer接口并重写相关update方法即可,在目标实现中我们发现触发的时候执行的就是观察者的update方法。

3.测试

package com.dpb.observer2;
public class Client {
  public static void main(String[] args) {
    //创建目标对象Obserable
    ConcreteSubject subject = new ConcreteSubject();
    //创建观察者
    ObserverA obs1 = new ObserverA();
    ObserverA obs2 = new ObserverA();
    ObserverA obs3 = new ObserverA();
    //将上面三个观察者对象添加到目标对象subject的观察者容器中
    subject.addObserver(obs1);
    subject.addObserver(obs2);
    subject.addObserver(obs3);
    //改变subject对象的状态
    subject.set(3000);
    System.out.println("===============状态修改了!");
    //观察者的状态发生了变化
    System.out.println(obs1.getMyState());
    System.out.println(obs2.getMyState());
    System.out.println(obs3.getMyState());
    subject.set(600);
    System.out.println("===============状态修改了!");
    //观察者的状态发生了变化
    System.out.println(obs1.getMyState());
    System.out.println(obs2.getMyState());
    System.out.println(obs3.getMyState());
    //移除一个订阅者
    subject.deleteObserver(obs2);
    subject.set(100);
    System.out.println("===============状态修改了!");
    //观察者的状态发生了变化
    System.out.println(obs1.getMyState());
    System.out.println(obs2.getMyState());
    System.out.println(obs3.getMyState());  
  }
}

20190216235018273.png

这样就实现了官方提供观察者模式,其实这里的Observable和Observer和我们前面自定义的Subject和Observer差不多,只是考虑的比我全面罢了。


四、开发中的常用场景:


聊天室程序的,服务器转发给所有客户端

网络游戏(多人联机对战)场景中,服务器将客户端的状态进行分发

邮件订阅

Servlet中,监听器的实现

Android中,广播机制

JDK的AWT中事件处理模型,基于观察者模式的委派事件模型(DelegationEventModel)

• 事件源----------------目标对象

• 事件监听器------------观察者

京东商城中,群发某商品打折信息



相关文章
|
6月前
|
设计模式 监控 Java
设计模式 - 观察者模式(Observer):Java中的战术与策略
【4月更文挑战第7天】观察者模式是构建可维护、可扩展系统的关键,它在Java中通过`Observable`和`Observer`实现对象间一对多的依赖关系,常用于事件处理、数据绑定和同步。该模式支持事件驱动架构、数据同步和实时系统,但需注意避免循环依赖、控制通知粒度,并关注性能和内存泄漏问题。通过明确角色、使用抽象和管理观察者注册,可最大化其效果。
125 2
|
3月前
|
设计模式 存储 前端开发
【十四】设计模式~~~行为型模式~~~观察者模式(Java)
文章详细介绍了观察者模式(Observer Pattern),这是一种对象行为型模式,用于建立对象之间的一对多依赖关系。当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。文中通过交通信号灯与汽车的案例以及多人联机对战游戏的设计方案,阐述了观察者模式的动机和应用场景。接着,文章介绍了观察者模式的结构、角色、优点、缺点以及适用情况,并通过代码示例展示了如何在Java中实现观察者模式。此外,还探讨了观察者模式在MVC架构中的应用以及Java中对观察者模式的支持。
【十四】设计模式~~~行为型模式~~~观察者模式(Java)
|
4月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
80 1
|
4月前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
62 1
|
4月前
|
设计模式 Java
Java面试题:什么是观察者模式以及如何在Java中实现?
Java面试题:什么是观察者模式以及如何在Java中实现?
34 0
|
4月前
|
设计模式 Java
Java面试题:描述观察者模式的工作原理及其在Java中的应用。
Java面试题:描述观察者模式的工作原理及其在Java中的应用。
36 0
|
4月前
|
设计模式 SQL 安全
Java面试题:设计一个线程安全的内存管理器,使用观察者模式来通知所有线程内存使用情况的变化。如何确保在添加和移除内存块时的线程安全?如何确保任务的顺序执行和调度器的线程安全?
Java面试题:设计一个线程安全的内存管理器,使用观察者模式来通知所有线程内存使用情况的变化。如何确保在添加和移除内存块时的线程安全?如何确保任务的顺序执行和调度器的线程安全?
38 0
|
4月前
|
设计模式 存储 缓存
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
39 0
|
5月前
|
存储 Java 测试技术
技术经验解读:【Java】事件驱动模型和观察者模式
技术经验解读:【Java】事件驱动模型和观察者模式
|
5月前
|
设计模式 存储 Java
Java设计模式之观察者模式详解
Java设计模式之观察者模式详解
下一篇
无影云桌面