首页 > 其他分享 >设计模式-观察者模式

设计模式-观察者模式

时间:2024-07-03 12:27:50浏览次数:16  
标签:java observer Observer void 观察者 模式 设计模式 public

一、观察者模式的核心思想

观察者(Observer)模式又名发布一订阅(Publish/Subscribe)模式。GOF 给观察者模式如下定义:定义对象间的一种一对多的依赖关系,让多个观察者对象同时关注同一个对象,当该对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
如下图所示,观察者模式中包含5类对象。
在这里插入图片描述

  • 目标接口 Subject:目标接口定义了增加观察者 attach()、删除观察者 detach()和通知观察者notifyObservers()3个接口,并定义自身的操作函数operation()。
  • 抽象目标类 AbstractSubject:该类定义了观察者的集合对象 vect,用来存储被添加的观察者对象列表;并实现增加观察者 attach()、删除观察者 detach()和通知观察者 notifyObservers()3个函数来更新该列表,以及通知所有的观察者对象更新自己。
  • 具体目标类MySubiect:继承自抽象目标类 AbstractSubiect,并编写具体的操作函数实现operation(),在该函数中可以调用 notifyObservers()来通知所有的观察者更新自己。
  • 观察者接口Observer:为那些在目标类发生改变时需要获得通知的对象定义一个统一的接口 update(),当调用 notifyObservers()时将会调用 update()函数来更新自己。
  • 具体观察者:可以定义多个观察者对象,如 Observer1、Observer2,用来编写统一的更新函数。客户端 Test 则可以通过为Subject类添加观察者 Observer 来实现监控。

下面来看具体的实现。

(1) 观察者接口 Observer.java定义了一个统一的更新接口update()。其源代码如下程序所示。

package behavior.observer;


/**
* @author Minggg
* 观察者接口
*/
public interface Observer {

	public void update();
}

(2) 观察者实现类 Observer1.java 是一个观察者的具体实现,其更新函数用来往控制台输出一个字符串。其源代码如下程序所示。

package behavior.observer;


/**
* @author Minggg
* 具体观察者
*/
public class Observer1 implements Observer {

	public void update(){ 
		System.out.println("观察者1得到通知!");
	}
}

(3) 观察者实现类 Observer2.java是另一个观察者的具体实现,其更新函数用来往控制台输出个字符串。其源代码如下程序所示。

package behavior.observer;


/**
* @author Minggg
* 具体观察者
*/
public class Observer2 implements Observer {

	public void update(){ 
		System.out.println("观察者2得到通知!");
	}
}

(4) 被观察者接口Subject.java中定义了3个操作观察者的接口函数,并定义了一个具体的操作函数接口,表示自身的功能。其源代码如下程序所示。

package behavior.observer;


/**
* @author Minggg
* 被观察者接口
*/
public interface Subject {

	// 增加观察者
	public void attach(Observer observer);
	// 删除观察者
	public void detach(Observer observer);
	// 通知所有观察者
	public void notifyObservers();
	// 自身的操作接口
	public void operation();
}

(5) 被观察者抽象类 AbstractSubject.java中提供了一个 Vector列表 vect,用来保存所有的观察者对象,并编写实现函数来操作该列表对象。其源代码如下程序所示。

package behavior.observer;

import java.util.Enumeration;
import java.util.Vector;


/**
* @author Minggg
* 被观察者抽象类
*/
public abstract class AbstractSubject implements Subject {

	private Vector<Observer> vect = new Vector<Observer>();
	
	@Override
	public void attach(Observer observer) {
		vect.add(observer);
	}

	@Override
	public void detach(Observer observer) {
		vect.remove(observer);
	}

	@Override
	public void notifyObservers() {
		Enumeration<Observer> em = vect.elements();
		while (em.hasMoreElements()) {
			em.nextElement().update();
		}
	}

}

(6) 被观察者实现类 MySubject.java是一个具体的目标类,它仅仅实现自身的操作函数,并适时调用 notifyObservers()来通知所有的观察者。其源代码如下程序所示。

package behavior.observer;


/**
* @author Minggg
* 具体被观察者
*/
public class MySubject extends AbstractSubject {

	public void operation() {
		System.out.println("修改自己");
		// 通知观察者
		notifyObservers();
	}

}

到此就完成了所有的开发。使用它们的方法也很简单,首先创建一个目标类MySubject 的对象subject,并可以为该对象添加多个观察者,当调用 operation()时会自动实现对观察者的通知。其源代码如下程序所示。

package behavior.observer;

public class Test {

	public static void main(String[] args) {
		Subject subject = new MySubject();
		// 增加观察者
		subjeet.attach(new Observer1());
		subject.attach(new Observer2());
		subject.operation();
	}

}

运行该程序的输出如下:

修改自己
观察者1得到通知!
观察者2得到通知!

从程序的输出可以看出,通过给subject添加观察者对象,就实现了在自身操作时对观察者的通知。

二、何时使用观察者模式

Observer 模式的优点是实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,类别清晰,并抽象了更新接口,使得可以有各种各样不同的观察者。因此,使用观察者模式可以实现业务与数据逻辑的通知机制。

观察者模式的效果有以下几个优点

  • 观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
  • 观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。

观察者模式有下面的一些缺点

  • 如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很长时间。
  • 如果在被观察者之间有循环依赖的话,被观察者会触发它们之间的循环调用,导致系统崩溃。
  • 虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。

三、Java中的应用–Observable和 Observer 观密者实现

实际上,观察者模式在Java提供的开发包中已经提供了实现。在java.util 包中有如下两个类。

  • Observer.java:一个观察者接口。
  • Observable.java:一个被观察者对象。

Observer.java 方法与我们以上讲解的观察者接口类似,提供了一个更新方法。其源代码如下程序所示。

package java.util;

public interface Observer {
	void update(Observable o, Object arg);
}

Observable.java 是一个观察者目标类,它也类似于上面提到的抽象观察者类,它提供了一个Vector 列表用来保存观察者对象,并提供了增加、删除、通知观察者的具体实现。源代码如下程序所示。

package java.util;

publie class Observable {

	private boolean changed = false;
	private Vector obs;
	
	pubic Observable() {
		obs = new Vector();
	}
	
	public synchronized void addObserver(Observer o) {
		if (o == null) {
			throw new NullPointerException();
		}
		if (!obs.contains(o)){
			obs addElement(o);
		}
	}

	pubfic synchronized void deleteObserver(Observer o) {
		obs.removeElement(o);
	}

	public void notifyObservers() {
		notifyObservers(nul1);
	}

	public void notifyObservers(Object arg) {
		Object[] arrLocal;
		synchronized (this) {
			if(!changed) {
				return;
			}
			arrLocal = obs.toArray();
			clearChanged();
		}
		for (int i = arrLocal.length-1; i>=0; i--) {
			((Observer)arrLocal[i]).update(this, arg);
		}
	}

	public synchronized void deleteObservers() {
		obs.removeAllElements();
	}

	protected synchronized void setChanged() {
		changed = true;
	}
	
	protected synchronized void clearChanged() {
		changed = false;
	}
	
	public synchronized boolean hasChanged() {
		return changed;
	}
	
	public synchronized int countObservers() {
		return obs.size();
	}
}

因此,我们要使用观察者模式时,只需要使用以上两个类来编写自己的子类即可。

标签:java,observer,Observer,void,观察者,模式,设计模式,public
From: https://blog.csdn.net/qq_35885952/article/details/140145736

相关文章

  • 设计模式-策略模式
    一、策略模式的核心思想策略模式定义了一系列的算法,并将每一个算法封装起来,使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。策略模式将一系列的算法包装为一个接口抽象类的子类,并由调用者决定调用某一个子类。其中定义了3种角色。策略接口类ICacu......
  • 前后端分离:四种开发模式与实践指南
    前后端分离:四种开发模式与实践指南什么是前后端分离当业务变得越来越复杂或产品线越来越多时,原有的开发模式就无法满足业务需求了。产品越来越多,展现层的变化越来越快、越来越多,此时应该进行前后端分离的分层抽象,简化数据获取过程。比如,目前比较常用的是前端人员自行实......
  • 设计模式
    设计模式六种设计原则单一职责原则组件或模块在封装过程中要保证功能的完善,尽量不要侵入其他的组件,使得组件间关联关系松散里氏替换原则多用组合,少用继承。继承的使用场景是两个类存在isa的关系,单纯的为了复用某个逻辑片段,应该避免使用继承,继承使两个类建立了强关联,且java......
  • WebAPI项目框架仓储模式+导入SqlSuag
    仓储(Respository)是对数据库访问的一个封装解决方案新建Respository文件夹,新建类库Web.Core.IRepository,Web.Core.Repository解决方案新建Services文件夹,新建类库Web.Core.IServices,Web.Core.Services在类库Web.Core.Model下面新建Entity文件夹SqlSugar是国人开发者开发的一......
  • 设计模式1-单例模式
    #单例模式    构造函数私有化。        私有化是为了阻止外部代码直接通过new关键字来实例化对象,从而确保单例唯一性,防止有子类继承破坏单例模式的唯一性    改单列对象必须由单例类自己创建    内部提供一个方法给外界调用对象.#饿汉普通实现p......
  • C++与C#创建位图,是否需要区分RGB和BGR模式
    在处理位图时,确实需要区分RGB和BGR模式,因为不同的库和API对颜色通道的排序有不同的约定。具体到C++与C#,这一点也是需要注意的。C++创建位图使用GDI+或WIC(WindowsImagingComponent):当你在C++中使用这些WindowsAPI创建或操作位图时,通常会指定像素格式,比如PixelFormat2......
  • Redis Sentinal(哨兵模式详解)
    参考文章https://www.cnblogs.com/wzh2010/p/180309071、什么是哨兵模式在实际生产环境中,服务器难免会遇到一些突发状况:服务器宕机,停电,硬件损坏等等,一旦发生,后果不堪设想。哨兵模式的核心还是主从模式的演变,只不过相对于主从模式,在主节点宕机导致不可写的情况下,多了探活,以及竞......
  • php简单的单例模式
    本文由ChatMoney团队出品单例模式是一种常用的设计模式,它的核心思想是确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。在PHP中实现单例模式通常有三种形式:饿汉式(Eager)、懒汉式(Lazy)和登记式(Register)。使用注意事项:不要使用反射(Reflection)机制来创建单例,因为......
  • 了解php当中简单的单例模式
    本文由ChatMoney团队出品单例模式是一种常用的设计模式,它的核心思想是确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。在PHP中实现单例模式通常有三种形式:饿汉式(Eager)、懒汉式(Lazy)和登记式(Register)。使用注意事项:不要使用反射(Reflection)机制来创建单例,因为......
  • vim学习笔记——三种基本模式和相关操作
    vim的三种模式一般模式以vim打开一个文件就直接进入一般模式了。在这个模式中,你可以使用hjkl按键移动光标,也可以使用删除字符或删除整行来处理文件内容,也可以使用复制粘贴处理文件内容。编辑模式在一般模式中按下A,a,I,i,O,o,R,r任何一个按键,就可以进入编辑模式,在界面左下方会......