最近在学习《head first 设计模式》,站在巨人的肩膀上学习设计模式,一定会有很大的收获。通过了解设计模式的uml图,来看java源码,让我对java中的一些实现又多了更深层次的了解。在这里,也记录一下学习历程,并与大家分享学习心得。
观察者模式的类图
- 观察者模式运用接口和组合的方式来进行设计。
- 类似于报纸的订阅,被订阅信息称为主题(Subject),订阅者称为观察者。当主题有更新时,会通知观察者。
- 主题和观察者之间是多对一的关系。一个主题可以引入多个观察者对象。
java中的观察者模式
java中专门提供了一个观察者模式的API,有时候用到观察者的设计思想时,可以继承java中的Observable类来实现。
使用例子
实现一个主题类
public class PaperObservable extends Observable{
private String date;
private String title;
private String content;
public void todayNewsChange(){
setChanged();
notifyObservers();
}
public void setTodayNews(String date,String title,String content){
this.date = date;
this.title = title;
this.content = content;
}
public void getObserversCount(){
int count = super.countObservers();
System.out.println("当前订阅者:"+count);
}
@Override
public String toString() {
return "PaperObservable{" +
"date='" + date + '\'' +
", title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}
注意 这里有个在调用通知方法之前要设置setChanged();这样才能实现通知观察者的效果。
实现两个观察者
新闻观察者
public class ConsumerPaperObserver implements Observer {
private Observable o;
public void update(Observable o, Object arg) {
this.o = o;
if (o instanceof PaperObservable){
System.out.println("民生类,今天订阅的新内容是:"+o.toString());
}
}
}
民生类新闻观察者
public class NewsPaperObserver implements Observer {
private Observable o;
public void update(Observable o, Object arg) {
this.o = o;
if (o instanceof PaperObservable){
System.out.println("新闻类,今天订阅的新内容是:"+o.toString());
}
}
}
打印结果
public class App
{
public static void main( String[] args ) {
PaperObservable paperObservable = new PaperObservable();
//更新今天的主题内容
paperObservable.setTodayNews("2017-09-07","lzl修复100+bug","程序员一天内努力修复100+bug");
//添加订阅者
NewsPaperObserver newsPaperObserver = new NewsPaperObserver();
ConsumerPaperObserver consumerPaperObserver = new ConsumerPaperObserver();
paperObservable.addObserver(newsPaperObserver);
paperObservable.addObserver(consumerPaperObserver);
paperObservable.todayNewsChange();
}
}
民生类,今天订阅的新内容是:PaperObservable{date='2017-09-07', title='lzl修复100+bug', content='程序员一天内努力修复100+bug'}
新闻类,今天订阅的新内容是:PaperObservable{date='2017-09-07', title='lzl修复100+bug', content='程序员一天内努力修复100+bug'}
看看java设计模式的源码
其实java只提供了两个主要类Observable(主题)类和Observer(观察者)接口类。
Observer
她的作用只提供了更新的方法
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
Observable的实现
有以下提供
* 线程安全的Observer对象集合。
* 添加、删除、通知观察者的方法
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
//添加方法
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
//删除方法
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
//通知方法
public void notifyObservers() {
notifyObservers(null);
}
/**
Object arg 这个对象是传入任何的数据对象说明,为空时候说明没有说明。
*/
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的观察者模式没有按照严格的接口编程,而是使用了继承的方式。这样的扩展性不好,设计上没有弹性。我们可以模拟实现一个面向接口的观察者模式。
主题接口
public interface MyObserverble {
/**
* 删除观察者
*/
void removeObserver(MyObserver myObserver);
/**
* 添加观察者
* @param myObserver
*/
void addObserver(MyObserver myObserver);
/**
* 通知观察者,某个
* @param myObserver
*/
void notifyObserver(MyObserver myObserver);
/**
* 通知所有的观察者
*/
void notifyObserver();
}
实现
public class MyObserverbleImpl implements MyObserverble {
private List<MyObserver> observers = null;
public MyObserverbleImpl(){
observers = new ArrayList<MyObserver>();
}
public void removeObserver(MyObserver myObserver) {
observers.remove(myObserver);
}
public void addObserver(MyObserver myObserver) {
observers.add(myObserver);
}
public void notifyObserver(MyObserver myObserver) {
observers.get(observers.indexOf(myObserver)).update(this, myObserver);
}
public void notifyObserver() {
for (MyObserver myObserver : observers){
myObserver.update(this, myObserver);
}
}
}
主题类的实现
public class MyPaperObservable extends MyObserverbleImpl{
private String date;
private String title;
private String content;
public void todayNewsChange(){
super.notifyObserver();
}
public void setTodayNews(String date,String title,String content){
this.date = date;
this.title = title;
this.content = content;
}
@Override
public String toString() {
return "PaperObservable{" +
"date='" + date + '\'' +
", title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}
这里观察者接口和类就不列举了,和Observer类没有说明区别。
只是改写了主题类,将其设计为接口,这样不同的主题可以实现接口。灵活性比较高
不过类的创建还是面向对象创建的。
public class ObserverbleMain
{
public static void main( String[] args ) {
MyPaperObservable paperObservable = new MyPaperObservable();
//更新今天的主题内容
paperObservable.setTodayNews("2017-09-0909","lzl修复100+bug","程序员一天内努力修复100+bug");
//添加订阅者
MyNewsPaperObserver newsPaperObserver = new MyNewsPaperObserver();
ConsumerPaperObserver consumerPaperObserver = new ConsumerPaperObserver();
paperObservable.addObserver(newsPaperObserver);
paperObservable.addObserver(consumerPaperObserver);
paperObservable.todayNewsChange();
}
}
uml图如下
详细的代码可以从github上下载到
https://github.com/hpulzl/lzl_workspace/tree/master/gof_demo