观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让他们能够更新状态。
抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或者接口来实现。抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体的主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知,具体主题角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要具体观察者角色可以保存一个指向具体主题角色的 引用。通常用一个子类实现。
UML类图:
/**
* 抽象观察者
* @author lm
*
*/
public interface Observer {
public void Upate(Object obj);
}
package com.observers;
/**
* 具体观察者角色
* @author lm
*
*/
public class ConcreateObserver implements Observer{
@Override
public void Upate(Object obj) {
// TODO Auto-generated method stub
System.out.println("Recevied: "+ obj );
}
}
package com.observers;
/**
* 抽象主题角色
* 1.增加观察者方法
* 2.删除观察者方法
* 3.通知
* @author lm
*
*/
public interface Subject {
void Attach(Observer observer);
void Delete(Observer observer);
void NotifyObservers(Object object);
}
package com.observers;
import java.util.ArrayList;
import java.util.List;
/**
* 具体主题
* @author lm
*
*/
public class ConcreteSubject implements Subject{
private List<Observer> list = new ArrayList<Observer>();
@Override
public void Attach(Observer observer) {
// TODO Auto-generated method stub
list.add(observer);
}
@Override
public void Delete(Observer observer) {
// TODO Auto-generated method stub
list.remove(observer);
}
@Override
public void NotifyObservers(Object object) {
// TODO Auto-generated method stub
for (Observer observer : list) {
observer.Upate(object);
}
}
/**
* 供客户端调用
*/
public void Invoke(){
for (int i = 0; i < 10; i++) {
System.out.println(i);
this.NotifyObservers(i);
}
}
}
package com.observers;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ConcreteSubject subject =new ConcreteSubject();
Observer observer1 = new ConcreateObserver();
Observer observer2 = new ConcreateObserver();
Observer observer3 = new ConcreateObserver();
subject.Attach(observer1);
subject.Attach(observer2);
subject.Attach(observer3);
subject.Delete(observer3);
subject.Invoke();
}
}
0
Recevied: 0
Recevied: 0
1
Recevied: 1
Recevied: 1
2
Recevied: 2
Recevied: 2
3
Recevied: 3
Recevied: 3
4
Recevied: 4
Recevied: 4
5
Recevied: 5
Recevied: 5
6
Recevied: 6
Recevied: 6
7
Recevied: 7
Recevied: 7
8
Recevied: 8
Recevied: 8
9
Recevied: 9
Recevied: 9
//主题接口
interface Subject {
//添加观察者
void addObserver(Observer obj);
//移除观察者
void deleteObserver(Observer obj);
//当主题方法改变时,这个方法被调用,通知所有的观察者
void notifyObserver();
interface Observer {
//当主题状态改变时,会将一个String类型字符传入该方法的参数,每个观察者都需要实现该方法
public void update(String info);
}
public class TeacherSubject implements Subject {
//用来存放和记录观察者
private List<Observer> observers=new ArrayList<Observer>();
//记录状态的字符串
private String info;
@Override
public void addObserver(Observer obj) {
observers.add(obj);
}
@Override
public void deleteObserver(Observer obj) {
int i = observers.indexOf(obj);
if(i>=0){
observers.remove(obj);
}
}
@Override
public void notifyObserver() {
for(int i=0;i<observers.size();i++){
Observer o=(Observer)observers.get(i);
o.update(info);
}
}
//布置作业的方法,在方法最后,需要调用notifyObserver()方法,通知所有观察者更新状态
public void setHomework(String info){
this.info=info;
System.out.println("今天的作业是"+info);
this.notifyObserver();
}
}
具体观察类:
public class StudentObserver implements Observer {
//保存一个Subject的引用,以后如果可以想取消订阅,有了这个引用会比较方便
private TeacherSubject t;
//学生的姓名,用来标识不同的学生对象
private String name;
//构造器用来注册观察者
public Student(String name,Teacher t) {
this.name=name;
this.t = t;
//每新建一个学生对象,默认添加到观察者的行列
t.addObserver(this);
}
@Override
public void update(String info) {
System.out.println(name+"得到作业:"+info);
}
}
测试程序:
public class TestObserver {
public static void main(String[] args) {
TeacherSubject teacher=new TeacherSubject();
StudentObserver zhangSan=new StudentObserver("张三", teacher);
StudentObserver LiSi=new StudentObserver("李四", teacher);
StudentObserver WangWu=new StudentObserver("王五", teacher);
teacher.setHomework("第二页第六题");
teacher.setHomework("第三页第七题");
teacher.setHomework("第五页第八题");
}
}
打印结果:
今天的作业是第二页第六题
张三得到作业:第二页第六题
李四得到作业:第二页第六题
王五得到作业:第二页第六题
今天的作业是第三页第七题
张三得到作业:第三页第七题
李四得到作业:第三页第七题
王五得到作业:第三页第七题
今天的作业是第五页第八题
张三得到作业:第五页第八题
李四得到作业:第五页第八题
王五得到作业:第五页第八题
以上都是推送模式
如何使对象变为观察者
继承观察者接口(java.util.Observer),然后调用Observable对象的addObserver()方法.不想再当观察者时,调用deleteObserver()就可以了.
被观察者(主题)如何发出通知
观察者如何接收通知
被观察者TeacherSubject:
import java.util.Observable;
public class Teacher extends Observable {
//布置作业的状态信息字符串
private String info;
public void setHomework(String info) {
this.info=info;
System.out.println("布置的作业是"+info);
setChanged();
notifyObservers();
}
public String getInfo() {
return info;
}
}
观察者StudentObserver:
import java.util.Observable;
import java.util.Observer;
public class Student implements Observer{
private Observable ob;
private String name;
public Student(String name,Observable ob) {
this.ob = ob;
this.name=name;
ob.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
Teacher t=(Teacher)o;
System.out.println(name+"得到作业信息:"+t.getInfo());
}
测试代码和打印结果我就不再写了,和上面的例子是一样一样的,在这个例子中我使用的是"pull"的方式拉数据,在需要传递状态的TeacherSubject中定义了一个info字符串的get方法,在观察者对象中调用get方法得到所需数据,如果希望使用push的方式,只需要在TeacherSubject类的notifyOservers()方法中传入String类型的info字符串即可在update()方法中直接通过第二个参数获取到arg,即使前面传过来的info字符串.
我觉得另一篇写的也不错 http://ifeve.com/observer-design-pattern-in-java-example-tutorial/ 可以看看