举例
先让我们看一个简单的现实生活中的观察者设计模式。
我们都知道老师与学生家长的关系
老师会把每次考试的成绩告诉家长(主题)
只要是老师所教的班级的学生的家长才能收到,别的班级的家长不能收到
当学生毕业后,学生家长就无法收到学生成绩
只要产生新的考试,家长才会收到消息
根据上述的例子:老师(主题)+学生家长(观察者)=观察者模式
下面就是观察者的总体模型。
定义
对象之间的一对多依赖,当一个对象改变状态是,他所对的依赖着都会收到通知并自动更新。
接口图:(这个图的例子不是上述例子,但是大致接口和类相似)
实现
上述的例子用代码实现:
//观察者借口
public interface Observer {
//被通知
void notified(String math,String english);
}
//主题借口
public interface Subject {
//注册观察者
void registerObserver(Observer o);
//移除观察者
void removeObserver(Observer o);
//通知观察者
void notifyObserver();
}
//观察者实现类
public class Parents implements Observer{
//把家长注册到老师里
public Parents(Subject sub) {
sub.registerObserver(this);
}
//子类通知
public void notified(String math,String english){
System.out.println("接受到消息:"+" "+math+" "+english);
}
}
import java.util.ArrayList;
import java.util.List;
//主题实现类
public class Teacher implements Subject{
List<Observer> observers;
String math,english;
Teacher(){
observers=new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
if(observers.contains(o)){
observers.remove(o);
}
}
@Override
public void notifyObserver() {
for(Observer o:observers){
o.notified(math,english);
}
}
public void examine(String math,String english){
this.math=math;
this.english=english;
notifyObserver();
}
}
//测试类
public class Test {
public static void main(String[] args) {
//设置一个主题
Teacher teacher = new Teacher();
//加入一个观察者
Parents parents=new Parents(teacher);
//发送消息
teacher.examine("math考试", "english考试");
}
}
java内置的观察者模式:
在java.util 包下面的 Observer 接口 和 Observable类
java内置的观察者模式如何运作:
如何把对象变成观察者。
可观察者要如何送出通知。
观察者如何接收通知。
用java内置类实现例子。
import java.util.Observable;
//主题实现类
public class Teacher extends Observable{
String math,english;
public void examine(String math,String english){
this.math=math;
this.english=english;
setChanged();
notifyObservers();
}
public String getMath() {
return math;
}
public String getEnglish() {
return english;
}
}
import java.util.Observable;
import java.util.Observer;
import javax.security.auth.Subject;
//观察者实现类
public class Parents implements Observer{
//把家长注册到老师里
public Parents(Observable observable) {
observable.addObserver(this);
}
//子类通知
public void notified(String math,String english){
System.out.println("接受到消息:"+" "+math+" "+english);
}
@Override
public void update(Observable o, Object arg) {
Teacher teacher=(Teacher)o;
notified(teacher.getMath(), teacher.getEnglish());
}
}
大家如果还不明白上面自带的观察者是怎么1实现的可以看jdk的源码:
public void notifyObservers(Object arg) {
Object[] arrLocal;
//同步
synchronized (this) {
//有一个changed属性判断状态是否改变
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
//和我们自己写的一样运行观察者队列的的update方法
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
缺点
java内置式实现类的缺点:
当然熟练的程序员可能已经会发现内置的观察者存在的问题,他把observable定义成类,因为java不支持单继承所以当我们要的类就不能继承别的类了。
observable中的setChanged方法都定义成了protected类型,所以除了子类外无法使用该函数
补充
观察者模式在关于目标(主题)角色、观察者角色通信的具体实现中,有两个版本。
1) 拉模式:目标角色在发生变化后,仅仅告诉观察者角色“我变化了”;观察者角色如果想要知道具体的变化细节,则就要自己从目标角色的接口中得到。拉模式是想要就主动表白获取。
2) 推模式:通知你发生变化的同时,通过一个参数将变化的细节传递到观察者角色中去。推模式是管你要不要,先给你啦。
这两种模式的使用,取决于系统设计时的需要。如果目标角色比较复杂,并且观察者角色进行更新时必须得到一些具体变化的信息,则“推模式”比较合适。如果目标角色比较简单,则“拉模式”就很合适啦。
观察者模式是非常常用的一个设计模式,再有些地方称它为设计模式的“皇后”,可想它的重要性。
在很多界面化编程中用到很多 事件监听机制(http://blog.csdn.net/qq_25673113/article/details/53244571) ,这个就是典型的观察者模式