HeadFirst——观察者模式
1.前言
观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
2.HeadFirst实例
为了减少篇幅,这里的实例与HeadFirst书上有所不同,但本质是相同的.
有一个报社负责将信息写在报纸上给他的用户,订阅了该报社的用户可时刻收到发来的信息,没订阅的就没有.
在这里有三个用户Tom,Cat,Dog,他们关心报纸的信息不同,Dog关注的football信息,Cat关注的pingpang信息,Tom关注的basketball信息.
为了达到被观察者设置一条信息,就通知给它们知道的话,步骤是这样的.
2.1 面向接口编程
为了代码的复用性,使用接口编程.这里定义三个接口:
1.Topic接口,定义一个主题接口,有注册,删除,通知观察者的抽象方法.
2.UserObserver接口,定义一个观察者接口,有更新数据的抽象方法.
3.Display接口,定义一个显示的接口,有显示的抽象方法.
public interface Topic {
void registerObserver(UserObserver observer);
void removeObserver(UserObserver observer);
void notifyObservers();
}
public interface UserObserver {
void update(String football,String basketball,String pingpang);
}
public interface Display {
void display();
}
2.2 实现各接口
2.2.1 实现Topic接口
这里定义NewTopic类实现Topic接口,该类中的字段有football,basketball,pingpang,用于存放相应的信息. 还有一个ArrayList的数组存放所有注册过的观察者,当执行notifyObservers()方法时会迭代数组并依次调用Observer的update方法.在这里也能体现接口的好处,因为你根本就不需要知道观察者是那一种类型.他只是实现了接口而已!
import java.util.ArrayList;
import java.util.List;
import cn.itcast.headFitst.observer.inter.Topic;
import cn.itcast.headFitst.observer.inter.UserObserver;
public class NewsTopic implements Topic {
private List<UserObserver> list = new ArrayList<UserObserver>();
private String football = null;
private String basketball = null;
private String pingpang = null;
@Override
public void registerObserver(UserObserver observer) {
list.add(observer);
}
@Override
public void removeObserver(UserObserver observer) {
if(list.indexOf(observer)>=0){
list.remove(observer);
}
}
@Override
public void notifyObservers() {
for(UserObserver o : list){
o.update(football,basketball,pingpang);
}
}
public void setMessage(String football,String basketball,String pingpang){
this.football = football;
this.basketball = basketball;
this.pingpang = pingpang;
notifyObservers();
}
}
2.2.2 实现UserObserver和Display接口
为了更新数据和显示到控制台,这二个接口都是要同时实现的。其中的构造器传入一个Topic接口,用于注册一个主题,这样它的内部就有一个主题了,当主题调用它的update()方法时就会显示一条数据!
以下为其中一个类:
import cn.itcast.headFitst.observer.inter.Display;
import cn.itcast.headFitst.observer.inter.Topic;
import cn.itcast.headFitst.observer.inter.UserObserver;
public class Cat implements Display, UserObserver {
private String pingpang = null;
private Topic topic = null;
public Cat(Topic topic){
this.topic = topic;
topic.registerObserver(this);
}
@Override
public void update(String football, String basketball, String pingpang) {
this.pingpang = pingpang;
display();
}
@Override
public void display() {
System.out.println("Cat关注的pingpang信息:" + pingpang);
}
}
2.2.3 Test测试
首先创建一个主题Topic,再创建三个对象并注册,当主题Topic设置一条信息时,控制台输出所有观察者关心的数据。
public class Test {
public static void main(String[] args) {
NewsTopic topic = new NewsTopic();
Dog dog = new Dog(topic);
Cat cat = new Cat(topic);
Tom tom = new Tom(topic);
topic.setMessage("中国足球进世界杯了!", "NBA在中国举办了!", "中国乒乓球又夺冠了!");
}
输出的信息:
Dog关注的football信息:中国足球进世界杯了!
Cat关注的pingpang信息:中国乒乓球又夺冠了!
Tom关注的basketball信息:NBA在中国举办了!
3.优缺点
在java中有内置的支持观察者模式的Observer和Observable两个类,这里不做介绍.
观察者模式的优点如下:
(1)它把观察者与被观察者分离,并将二者间的关系通过抽象观察者和抽象被观察者联系在一起,当一方发生变化时不会影响另一方的执行,从而降低了程序的耦合。
(2)可以支持多种不同的具体观察者实现,有利于程序的扩展。
(3)观察者的数目是可变的,主题可以实现动态的增加或移除观察者对象。
(4)被观察者在自身状态发生变化时,会主动通知观察者,如果不是被观察者主动通知,那就需要观察者通过定时任务的方式来监控被观察者的状态是否发生变化,被观察者主动通知的方式要比观察者定时监控方式性能更高。
观察者模式的缺点:
观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死。
其他的观察者模式博文:https://software.intel.com/zh-cn/blogs/2011/12/16/400009402