您的位置:首页 > 编程语言 > Java开发

JAVA设计模式之观察者模式

2020-02-17 04:55 381 查看

    当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。观察者模式是Java非常重要的一个设计模式。

观察者模式所涉及的角色有:

  ●  抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。

  ●  具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。

  ●  抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。

  ●  具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。

抽象主题(subject)角色:

import java.util.ArrayList;
import java.util.List;

public abstract class Subject {

private List<MyObserver>list = new ArrayList<>();

public void register(MyObserver myObserver){
if (!list.contains(myObserver)){
list.add(myObserver);
}
}

public void remove(MyObserver myObserver){
if (list.contains(myObserver)){
list.remove(myObserver);
}
}

public void notifyObserver(){
for (MyObserver myObserver : list) {
myObserver.update();
}
}

}

抽象观察者角色:

public interface MyObserver {

void update();
}

具体主题角色:

public class Repoter extends Subject {

private String msg;

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
if (change()) {
notifyObserver();
}
}

public Boolean change() {
if (msg.equals(getMsg())) {
return true;
} else {
return false;
}
}
}

第一个具体观察者对象:

public class PeopleDaily implements MyObserver {

private Subject subject;

public PeopleDaily(Subject subject) {
this.subject = subject;
subject.register(this);
}

@Override
public void update() {
System.out.println("人民日报发布最新报道:" + ((Repoter) subject).getMsg());
}

public void remove() {
subject.remove(this);
}
}

第二个具体观察者对象:

public class NewsFeeds implements MyObserver {

private Subject subject;

public NewsFeeds(Subject subject) {
this.subject = subject;
subject.register(this);
}

@Override
public void update() {
System.out.println("新闻联播发布最新报道:" + ((Repoter) subject).getMsg());
}

public void remove() {
subject.remove(this);
}
}

第三个具体观察者对象:

public class XinHuaNewsAgency implements MyObserver {
private Subject subject;

public XinHuaNewsAgency(Subject subject) {
this.subject = subject;
subject.register(this);
}

@Override
public void update() {
System.out.println("新华社发布最新报道:" + ((Repoter) subject).getMsg());
}

public void remove() {
subject.remove(this);
}
}

测试:

public class TestDemo {

@Test
public void demo(){
Repoter repoter = new Repoter();
NewsFeeds newsFeeds = new NewsFeeds(repoter);
XinHuaNewsAgency xinHuaNewsAgency = new XinHuaNewsAgency(repoter);
PeopleDaily peopleDaily = new PeopleDaily(repoter);

repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");

}
}

结果:

新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!

Process finished with exit code 0

删除一个观察者再试:

public class TestDemo {

@Test
public void demo(){
Repoter repoter = new Repoter();
NewsFeeds newsFeeds = new NewsFeeds(repoter);
XinHuaNewsAgency xinHuaNewsAgency = new XinHuaNewsAgency(repoter);
PeopleDaily peopleDaily = new PeopleDaily(repoter);

repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");
repoter.remove(xinHuaNewsAgency);
System.out.println("————————————————————————————————————————————————");
repoter.setMsg("华为发布最新旗舰机Mate30系列型号手机");
}
}

结果:

新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!
————————————————————————————————————————————————
新闻联播发布最新报道:华为发布最新旗舰机Mate30系列型号手机
人民日报发布最新报道:华为发布最新旗舰机Mate30系列型号手机

Process finished with exit code 0

对于观察者模式,JDK已经为我们提供了对应的接口和类。

JDK源代码:

package java.util;

/**
*
* 当一个类想要被告知可观察对象的变化时,它可以实现 Observer 接口。
* @author  Chris Warth
* @see     java.util.Observable
* @since   JDK1.0
*/
public interface Observer {
/**
*
* 每当观察对象发生变化时,都会调用此方法。应用程序调用 Observable 对象的 notifyObservers 方法,以便让所有对
* 象的观察者收到更改通知。
* @param   o     the observable object.
* @param   arg   an argument passed to the <code>notifyObservers</code>
*                 method.
*/
void update(Observable o, Object arg);
}

Observer是一个接口,只是一个方法update用于接收通知者的通知并做出相应,具体的逻辑肯定是需要开发者自己实现的了。

被观察者,JDK的源码如下:

package java.util;

/**
*
* 此类表示可观察对象,或模型 - 视图范例中的“数据”。它可以被子类化以表示应用程序想要观察的对象。
* 可观察对象可以有一个或多个观察者。观察者可以是实现接口 Observer 的任何对象。
* 在可观察的实例发生更改后,调用 Observable 的 notifyObservers 方法,应用程序会通过调用 update 来通知所有观察
* 者的更改。
* 未指定通知的递送顺序。 Observable类中提供的默认实现将按照它们注册的顺序通知Observers,但是子类可能会更改此顺
* 序,使用不保证顺序,在单独的线程上发送通知,或者可以保证它们的子类遵循此顺序,因为它们选择。
* 请注意,此通知机制与线程无关,并且与类 Object 的 wait 和 notify 机制完全分开。
* 当新创建可观察对象时,其观察者集合为空。当且仅当 equals 方法为它们返回true时,才认为两个观察者是相同的。
* @author  Chris Warth
* @see     java.util.Observable#notifyObservers()
* @see     java.util.Observable#notifyObservers(java.lang.Object)
* @see     java.util.Observer
* @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
* @since   JDK1.0
*/
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;

//构造方法
public Observable() {
obs = new Vector<>();
}

/**
* 将观察者添加到此对象的观察者集中,前提是它与集合中已有的某个观察者不同。未指定将通知发送给多个观察者的顺序。
* @param   o   an observer to be added.
* @throws NullPointerException   if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}

/**
*
* 从该对象的观察者集中删除观察者。将 null 传递给此方法将不起作用。
* @param   o   the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}

/**
*
* 如果此对象已更改,如 hasChanged 方法所示,则通知其所有观察者,然后调用 clearChanged 方法以指示此对象不再
* 更改。
* 每个观察者都使用两个参数调用 update 方法:observable对象和 null 。换句话说,此方法等效于:
* notifyObservers(null)
* @see     java.util.Observable#clearChanged()
* @see     java.util.Observable#hasChanged()
* @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}

/**
*
* 如果此对象已更改,如 hasChanged 方法所示,则通知其所有观察者,然后调用 clearChanged 方法以指示此对象不再
* 更改。
* 每个观察者都使用两个参数调用 update 方法:observable对象和 arg 参数。
* @param   arg   any object.
* @see     java.util.Observable#clearChanged()
* @see     java.util.Observable#hasChanged()
* @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers(Object arg) {
/*
*
* 临时数组缓冲区,用作当前Observers状态的快照。
*/
Object[] arrLocal;

synchronized (this) {
/*
* 我们不希望Observer在拥有自己的Monitor时进行任意代码的回调。我们从Vector中提取每个Observable并存
* 储Observer状态的代码需要同步,但是通知观察者不会(不应该)。这里任何潜在竞争条件的最坏结果是:
* 1)新添加的观察者将错过正在进行的通知
* 2)最近未注册的观察者将被错误地通知
*/
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();
}

/**
*
* 将此 Observable 对象标记为已更改;  hasChanged 方法现在将返回 true 。
*/
protected synchronized void setChanged() {
changed = true;
}

/**
*
* 表示此对象已不再更改,或者已向其所有观察者通知其最近的更改,因此 hasChanged 方法现在将返回 false 。
* 此方法由 notifyObservers 方法自动调用。
* @see     java.util.Observable#notifyObservers()
* @see     java.util.Observable#notifyObservers(java.lang.Object)
*/
protected synchronized void clearChanged() {
changed = false;
}

/**
*
* 测试此对象是否已更改。
* @return  <code>true</code> if and only if the <code>setChanged</code>
*          method has been called more recently than the
*          <code>clearChanged</code> method on this object;
*          <code>false</code> otherwise.
* @see     java.util.Observable#clearChanged()
* @see     java.util.Observable#setChanged()
*/
public synchronized boolean hasChanged() {
return changed;
}

/**
*
* 返回此 Observable 对象的观察者数。
* @return  the number of observers of this object.
*/
public synchronized int countObservers() {
return obs.size();
}
}

Java源码使用Vector,Vector相比于ArrayList来说,它是线程安全的。在添加和删除观察者时对两个方法使用了synchronized关键字,这都是在为多线程考虑。

观察者:实现观察者接口(java.util.Observer),然后调用任何Observable对象的addObserver()方法,注销观察者时,就调用deleteObserver()方法即可。

第一个观察者对象:

public class XinhuaNewsAgency implements Observer {

//被观察者对象
private Observable observable;

public XinhuaNewsAgency(Observable observable) {
this.observable = observable;
//将观察者对象加入到观察者集合中
observable.addObserver(this);

}

@Override
public void update(Observable o, Object arg) {

if(o instanceof Repoter){
System.out.println("新华社发布最新报道:" + ((Repoter) o).getMsg());
}
}

public void remove(){
//删除观察者
observable.deleteObserver(this);
}
}

第二个观察者对象:

public class PeopleDaily implements Observer {

//被观察者对象
private Observable observable;

public PeopleDaily(Observable observable) {
this.observable = observable;
//将观察者对象加入到观察者集合中
observable.addObserver(this);
}

@Override
public void update(Observable o, Object arg) {

if (o instanceof Repoter){
System.out.println("人民日报发布最新报道:" + ((Repoter) o).getMsg());
}
}

public void remove(){
//删除观察者
observable.deleteObserver(this);
}
}

第三个观察者对象:

public class NewsFeeds implements Observer {

//被观察对象
private Observable observable;

public NewsFeeds(Observable observable) {
this.observable = observable;
//将观察者对象加入到观察者集合中
observable.addObserver(this);
}

@Override
public void update(Observable o, Object arg) {

if (o instanceof Repoter){
System.out.println("新闻联播发布最新报道:" + ((Repoter) o).getMsg());
}

}

public void remove(){
//删除观察者
observable.deleteObserver(this);
}
}

被观察者:继承java.util.Observable类,调用setChanged()方法,标记状态改变。然后调用nofityObservers()方法或者notifyobservers(Object arg) 方法。

public class Repoter extends Observable {

private String msg;

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
this.setChanged();
this.notifyObservers(msg);
}

}

测试:

public class TestDemo {

@Test
public void demo(){
Repoter repoter = new Repoter();
NewsFeeds newsFeeds = new NewsFeeds(repoter);
PeopleDaily peopleDaily = new PeopleDaily(repoter);
XinhuaNewsAgency xinhuaNewsAgency = new XinhuaNewsAgency(repoter);
repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");
}
}

结果:

新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!

Process finished with exit code 0

结果发现顺序和注册的顺序并不一致。将新闻联播注销,在运行:

public class TestDemo {

@Test
public void demo(){
Repoter repoter = new Repoter();
NewsFeeds newsFeeds = new NewsFeeds(repoter);
PeopleDaily peopleDaily = new PeopleDaily(repoter);
XinhuaNewsAgency xinhuaNewsAgency = new XinhuaNewsAgency(repoter);

repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");
newsFeeds.remove();
System.out.println("————————————————————————————————————————————————");
repoter.setMsg("华为发布最新旗舰机Mate30系列型号手机");

}
}

结果:

新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!
————————————————————————————————————————————————
新华社发布最新报道:华为发布最新旗舰机Mate30系列型号手机
人民日报发布最新报道:华为发布最新旗舰机Mate30系列型号手机

Process finished with exit code 0

劣势:

Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,不如自己实现的观察者模式灵活。
Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能。

 

转载于:https://my.oschina.net/u/4149810/blog/3095319

  • 点赞
  • 收藏
  • 分享
  • 文章举报
choukao4407 发布了0 篇原创文章 · 获赞 0 · 访问量 49 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: