观察者模式是个非常常见的设计模式,窗体程序中、MVC等都大量使用了观察者模式。
观察者模式,可以理解为采用订阅、推送消息的方式实现一对多(其实还可以‘拉’消息,Java内置库中有相应实现,但‘推’更为巧妙,本文实现用的‘推’)。
概念
在对象之间定义一对多依赖,这样一来,当一个对象改变状态,依赖他的对象会收到通知,并自动更新。
主题与观察者
*《HeadFirst 设计模式》*一书中提到了订阅报纸,你想看报纸,可以向报社订阅,然后报社有新闻了便会给你发报纸,如果你不想看了,可以取消订阅。这其实就是观察者模式,我们将报社称作主题(Subject),你就是观察者(Observer)。
以下是观察者模式类图:
优势:
让主题和观察者之间松耦合,主题只知道观察者实现了某个接口,不知道观察者的具体类是谁、做了什么或其他细节;有新类型观察者出现时,主题(Subject)的代码不需要修改;我们可以独立地复用主题或观察者;改变两者任意一方,不会互相影响。
代码实现:
Subject.java:
public interface Subject{
public void addObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();//推送
}
Observer.java:
public interface Observer{
public void update(Object object);
}
DisplayElement.java:
public interface DisplayElement{
public void display();
}
ConcreteSubject.java:
import java.util.ArrayList;
public class ConcreteSubject implements Subject{
private ArrayList observers;//用于存储订阅的观察者
private float data1;
private float data2;
public float getData1() {
return data1;
}
public float getData2() {
return data2;
}
public ConcreteSubject()
{
observers=new ArrayList();
}
public void addObserver(Observer o)
{
observers.add(o);
}
public void removeObserver(Observer o)
{
int i = observers.indexOf(o);
if(i >= 0){
observers.remove(i);
}
}
public void notifyObservers()
{
for (int i = 0; i < observers.size();i++)
{
Observer observer=(Observer)observers.get(i);
observer.update(this);//更改消息
}
}
public void setDatas(float data1,float data2)
{
this.data1=data1;
this.data2=data2;
notifyObservers();
}
}
ConcreteObserver.java:
public class ConcreteObserver implements Observer, DisplayElement{
private float data1;
private float data2;
private Subject concreteSubject;
public ConcreteObserver(Subject concreteSubject)
{
this.concreteSubject=concreteSubject;
}
public void update(Object o)
{
this.data1=((ConcreteSubject)o).getData1();
this.data2=((ConcreteSubject)o).getData2();
display();
}
public void display()
{
System.out.println("data1:"+data1+","+"data2:"+data2);
}
}
测试代码:
public class Main {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
ConcreteObserver concreteObserver=new ConcreteObserver(concreteSubject);
concreteSubject.addObserver(concreteObserver);
concreteSubject.setDatas(12,12);
concreteSubject.setDatas(13,13);
concreteSubject.setDatas(14,14);
}
}
运行结果:
总结:
OO原则:
为交互对象之间松耦合设计而努力
**封装变化:**在观察者模式中,会改变的是主题状态,以及观察者的数目和类型。用这个模式,你可以改变依赖于主题状态的对象,却不必改变主题。这就叫提前规划。
**针对接口,不针对实现:**主题与观察者都使用接口,观察者利用主题的接口向主题注册,而主题利用观察者接口进行通知(推送消息)。
**多组合,少继承:**观察者模式利用组合将许多观察者组合进主题中。即本文中的ArrayList