好久没搞java了,要找工作了,复习下设计模式~~
观察者模式:描述的是一对多的关系,当”一”的状态发生变化时,会通知”多”的一端,前提是”多”个对象必须事先注册到”一”的对象上,让“一”知道它们的存在。
举个形象的例子:我们平时订阅杂志,每个订阅者(即观察者)必须到杂志社注册个人信息,杂志社为了在日后能够顺利分发杂志,此时必须保存每个订阅者的信息,当杂志社出版新杂志,它就会通过之前那个记录列表一个一个的分别通知它的每一位订阅者,只要你在它那里注册过,就会一直收到新的杂志。当然,你可以选择取消订阅,这样杂志社就不会再向你送新杂志了。只有杂志社一直存在,就会不停的有人订阅杂志或取消订阅,而这个动作是在整个运行机制中动态发生的。
为了松耦合,我们针对接口编程,这是一个主题的接口,声明三个方法,作用分别是注册订阅者、取消订阅、状态变化时通知所有订阅者
public interface Subject {
public void registerSub(Subscriber sub);
public void cancelSub(Subscriber sub);
public void notifySubs();
}
接下来是主题接口的实现类,ConcreteSubject.java
public class ConcreteSubject implements Subject {
private List<Subscriber> subs = new ArrayList<Subscriber>();
private String state1;
private String state2;
public void registerSub(Subscriber sub) {
subs.add(sub);
}
public void cancelSub(Subscriber sub) {
int index = subs.indexOf(sub);
if (index >= 0) {
subs.remove(sub);
}
}
public void notifySubs() {
for (Subscriber sub : subs) {
sub.update(state1, state2);
}
}
public void stateChanded(String state1, String state2){
this.state1 = state1;
this.state2 = state2;
notifySubs();
}
}
分析这个类:首先,因为当有新消息时会通知所有的订阅者,显然ConcreteSubject的实例必须知道有哪些对象注册到它上面来了,所以ConcreteSubject类中必须有一个集合类型变量:List subs; 用来保存每一个订阅者的引用。由于订阅者可以不同的类型,想要将不同类的对象保存到同一个集合中,最简单的办法就是让不同的订阅者类现实一个共同的接口,我们称之为Subscriber(订阅者),这样前面的集合变量类型就可以通过泛型指明了,即List<Subscriber> subs; 其次,分别实现Subject接口声明的三个方法;最后,我们模拟两个变量state1, state2,当它们发生变化时,会调用notifySubs()更新所有它的注册者。
通过上面的分析,我们需要一个Subscriber接口:
public interface Subscriber {
public void update(String state1, String state2);
}
假设有三个订阅者
小明:
public class XiaoMing implements Subscriber {
private Subject subject;
private String state1;
private String state2;
public XiaoMing(Subject subject) {
this.subject = subject;
subject.registerSub(this);
}
public void update(String state1, String state2) {
this.state1 = state1;
this.state2 = state2;
System.out.println("XiaoMing被通知了...");
}
}
后两个类与小明类大同小异
大明:
public class DaMing implements Subscriber {
private Subject subject;
private String state1;
private String state2;
public DaMing(Subject subject) {
this.subject = subject;
subject.registerSub(this);
}
public void update(String state1, String state2) {
this.state1 = state1;
this.state2 = state2;
System.out.println("DaMing被通知了...");
}
}
小红:
public class XiaoHong implements Subscriber {
private Subject subject;
private String state1;
private String state2;
public XiaoHong(Subject subject) {
this.subject = subject;
subject.registerSub(this);
}
public void update(String state1, String state2) {
this.state1 = state1;
this.state2 = state2;
System.out.println("XiaoHong被通知了...");
}
这三个实际的订阅者 实现了一个共同的接口,类似于一个标识,告诉主题“我是一个订阅者”,当注册后,如果有新消息请通知我。我们看到,Subscriber接口中只声明了一个方法update(),这个接口的作用在于为“主题”通知”订阅者”提供一个统一的方法。
测试:
public class Main {
public static void main(String[] args) {
//注册
ConcreteSubject subject = new ConcreteSubject();
XiaoMing xm = new XiaoMing(subject);
DaMing dm = new DaMing(subject);
XiaoHong xh = new XiaoHong(subject);
//Subject状态发生变化
subject.stateChanded("new1", "new2");
System.out.println();
subject.cancelSub(dm);
subject.stateChanded("new3", "new4");
}
}
可以看到,订阅者注册到主题之后,主题的状态发生变化(对象中变量被重设)时,会依次通知每个订阅者,而当订阅者取消订阅后,主题的新消息再不再通知它。
总结:
观察者模式的关键在于:一个订阅接口,多个订阅者实现类,主题中以一个集合的形式保存所以订阅者,这样就可以向每个订阅者发送消息
观察者模式的灵活性在于:如果有增加一个订阅者,完全不用修改ConcreteSubject类,直接让新添加的订阅者实现Subscriber接口,并在构造函数中向主题注册,完了就可以直接用了。