定义
在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
认识观察者模式
出版者+订阅者=观察者模式
如果你了解报纸的订阅是怎么回事,其实就知道观察者模式是怎么回
事,只是名称不太一样:出版者改称为“主题”(Subject),订阅者改称
为“观察者”(Observer)。
松耦合
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
为什么呢?关于观察者的一切,主题只知道观察者实现了某个接口(也就是Observer接口)。
主题不需要知道观察者的具体类是谁、做了些什么或其他任何细节。
任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。事实上,在运行时我们可以用新的观察者取代现有的观察者,主题不会受到任何影响。同样的,也可以在任何时候删除某些观察者。
有新类型的观察者出现时,主题的代码不需要修改。假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新的类里实现此观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。
我们可以独立地复用主题或观察者。如果我们在其他地方需要使用主题或观察者,可以轻易地复用,因为二者并非紧耦合。
改变主题或观察者其中一方,并不会影响另一方。因为两者是松耦合的,所以只要他们之间的接口仍被遵守,我们就可以自由地改变他们。
主题接口
public interface Subject {
//注册观察者
public void registerObserver(Observer o);
//移除观察者
public void removeObserver(Observer o);
//通知观察者
public void notifyObservers();
}
观察者接口
public interface Observer {
void update(float price);
}
书店实现了主题接口
public class Bookstore implements Subject{
List<Observer> observers;
private float price;
public Bookstore(){
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
if(observers.indexOf(o)>=0){
observers.remove(o);
}
}
@Override
public void notifyObservers() {
observers.forEach(o->o.update(price));
}
//当书本价格变动时通知观察者
public void priceChanged() {
notifyObservers();
}
//模拟书本价格的更新
public void setMeasurements(float price) {
this.price = price;
priceChanged();
}
}
我们可以把观察者,也就是观察着书店的书价格的人作为一个接口
public interface Person {
void display();
}
具体的观察者
public class SuQin implements Observer,Person{
private Subject bookstore;
private float price;
//把自己注册为书店价格变动的观察者
public SuQin(Subject subject){
this.bookstore=subject;
subject.registerObserver(this);
}
@Override
public void update(float price) {
this.price=price;
}
@Override
public void display(){
System.out.println("苏秦得到了通知,书的价格变动为:"+this.price+"元");
}
}
public class ZhangYi implements Observer,Person{
Subject subject;
private float price;
public ZhangYi(Subject subject){
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update(float price) {
this.price=price;
}
@Override
public void display(){
System.out.println("张仪得到了通知,书的价格变动为:"+this.price+"元");
}
}
测试一下
public class App {
public static void main(String[] args) {
Bookstore bookstore = new Bookstore();
SuQin suQin = new SuQin(bookstore);
ZhangYi zhangYi = new ZhangYi(bookstore);
bookstore.setMeasurements(80);
suQin.display();
zhangYi.display();
}
}
当书店书的价格变动时,苏秦和张仪两个人都会得到价格变动的通知。
实际上java API已经有了内置的观察者模式。java.util包(package)内包含最基本的Observer接口与Observable类,这和我们的Subject接口与Observer接口很相似。但是java.util.Observer是一个类而非一个接口,如果某类想同时具有Observable类和另一个超类的行为,就会陷入两难,毕竟Java不支持多重继承。这限制了Observable的复用潜力。
要点
- 观察者模式定义了对象之间一对多的关系。
- 主题(也就是被观察者)用一个接口更新观察者。
- 观察者与被观察者之间用松耦合的方式结合。被观察者不知道观察者的细节,只知道观察者都实现了同一个观察者接口。
- java有多种观察者模式的实现,包括通用的java.util.Observerable。