[设计模式]-观察者模式(Observer)☆

观察者模式

定义:

观察者模式是使用频率最高的设计模式之一,又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或者从属者(Dependents)模式

定义: 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新

类图:

  • Subject(目标):目标又称主题,指被观察的对象。
  • 目标中定义了一个观察者的集合,一个目标可以被任意数量的观察者观察
  • 目标提供对观察者注册和退订的维护
  • 当目标的状态发生变化时,负责通知所有注册的观察者
  • 目标类可以是接口、抽象类或具体类
  • ConcreteSubject(具体目标):具体目标是目标类的子类或实现。通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。
  • Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),可以在该方法中回调目标对象,以获取目标对象的数据
  • ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。
实现代码:
/*
 * 目标对象 - 它知道观察它的观察者,并提供注册、删除观察者的接口
 */
abstract class Subject {
    //Vector ArrayList 一个线程安全一个效率高
    protected Vector<Observer> observersVector = new Vector<>();
    //注册观察者
    public void attach(Observer observer){
        observersVector.addElement(observer);
    }
    //删除观察者
    public void detach(Observer observer){
        observersVector.removeElement(observer);
    }

    //抽象通知方法
    public abstract void notifyObservers();
}
/**
 * 观察者接口-定义一个更新接口给那些在目标发生改变时被通知的对象
 */
public interface Observer {
    //更新  - 传入目标对象,方便获取相应的目标对象的状态
    public void update(Subject subject);
}
/**
 * 具体目标对象 - 负责把有关状态存入到相应观察者对象,并在自己状态发生改变时,通知各个观察者
 */
public class ConcreteSubject implements Subject{
    private String subjectState;
    public void setState(String subjectState) {
        this.subjectState = subjectState;
        notifyObservers();
    }
    public String getState() {
        return subjectState;
    }

    @Override
    public void notifyObservers(){
        Enumeration<?> enumeration =observersVector.elements();
        while(enumeration.hasMoreElements()){
            ((Observer)enumeration.nextElement()).update(this);
        }
    }
}
/**
 * 具体观察者对象 - 实现更新方法,使自身状态与目标状态一致
 */
public class ConcreteObserver implements Observer{
	private String observerState;
	@Override
	public void update(Subject subject) {
		// 具体实现更新
		observerState = ((ConcreteSubject)subject).getState();
	}
}

在上述实现代码中,具体观察者类ConcreteObserver的update()方法在执行时需要使用到具体目标类ConcreteSubject中的状态(属性),因此在ConcreteObserver与ConcreteSubject之间有时候还存在关联或依赖关系,在ConcreteObserver中update需要一个ConcreteSubject实例,通过该实例获取存储在ConcreteSubject中的状态。如果ConcreteObserver的update()方法不需要使用到ConcreteSubject中的状态属性,则可以对观察者模式的标准结构进行简化,在具体观察者ConcreteObserver和具体目标ConcreteSubject之间无须维持对象引用。如果在具体层具有关联关系,系统的扩展性将受到一定的影响,增加新的具体目标类有时候需要修改原有观察者的代码,在一定程度上违反了“开闭原则”,但是如果原有观察者类无须关联新增的具体目标,则系统扩展性不受影响

推模型和拉模型

观察者模式的实现中,分推模型与拉模型两种方式

推模型假定目标对象知道观察者需要的数据;而拉模型是目标对象不知道观察者具体需要什么数据,没办法的情况下,只能把自身传给观察者,让观察者自己按需取值。上面的示例代码就是典型的拉模型。推模型如何实现也很简单,如下:

public void update(String subjectState){
		//推模型 - 直接传入数据
		observerState = subjectState;
	}
比较:首先推模型可能使得观察者对象难以复用,因为观察者定义的update方法是按需定义的,意味着当出现新情况时需要提供新的update或重新实现观察者;而拉模式不会有上述问题,但却可能导致具体观察者和具体目标对象之间产生关联或依赖关系。一堆废话之后总结就是视情况而定。


MVC的核心

为什么GOF四人组没有把MVC定义为一种设计模式,而是把它当做“一组用于构建用户界面的类集合”。在他们看来,MVC其实是其它三个经典的设计模式的演变:观察者模式(Observer)(Pub/Sub), 策略模式(Strategy)和组合模式(Composite)。MVC中models表示应用的数据,而views处理屏幕上展现给用户的内容。为此,MVC在核心通讯上基于推送/订阅模型。当一个model变化时它对应用其它模块发出更新通知(“publishes”),订阅者 (subscriber)——通常是一个Controller,然后更新对应的view。

Java中的观察者模式

概述

JAVA从AWT1.1开始的视窗系统的事件模型采用观察者模式,因此观察者模式在Java中的地位非常重要,在JDK的java.util包中,提供了Observable类以及Observer接口,它们构成了JDK对观察者模式的支持


(1) Observer接口:只定义了一个update()

(2) Observable类:被观察者都是Observable的子类。具体方法请参见Observable类源码

基于Java观察者模式的示例

//目标
class NewsPaper extends java.util.Observable{
	private String content;
	//出版发行报纸
	public void setContent(String content){
		this.content = content;
		//Java-观察者模式必需
		this.setChanged();
		//推模型主动通知
		this.notifyObservers(this.content);
	}
	public String getContent() {
		return content;
	}
}
//观察者
class Reader implements java.util.Observer{
	private String name;
	public Reader(String name){
		this.name = name;
	}

	@Override
	public void update(Observable o, Object arg) {
		// 推模型
		System.out.println(name+"收到报纸,内容:"+arg);
		// 拉模型
		System.out.println(name+"收到报纸,内容:"+((NewsPaper)o).getContent());
	}
}
public class ObserverClient {
	public static void main(String[] args) {
		NewsPaper paper = new NewsPaper();
		paper.addObserver(new Reader("cpp"));
		paper.addObserver(new Reader("hxq"));

		paper.setContent("你还好么");
	}
}

观察者模式总结

观察者模式的本质:触发联动

优点
  • 观察者模式实现了观察者和目标之间的抽象耦合。被观察者所知道的只是一个具体观察者列表,且有一个共同的接口。由于观察者和被观察者并没有紧密的耦合,因此它们可以属于不同的抽象化层次
  • 观察者模式实现了动态联动。通过注册的方式,在运行期间可以动态的管理注册的观察者,从而控制某个动作的联动范围,从而实现动态联动
  • 观察者模式支持广播 通信
缺点
  • 可能会引起无谓的操作。不管观察者需不需要,都会调用update方法
  • 如果在被观察者之间有循环依赖,被观察者会触发进行循环调用,导致系统崩溃
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值