定义
定义对象间的一对多的关系,使得每当一个对象的状态改变,则所有依赖与它的对象都会得到通知并被自动更新
使用场景
- 观察者和被观察者是抽象耦合,利于扩展
- 一个对象的改变将会导致一个或多个对象的改变,不清楚具体有多少对象以及这些被影响的对象是谁的情况
- 如果有这样一个影响链的情况下也可以使用,例如A的改变会影响B,B的改变会影响C......,可以使用观察者模式设计一个链式触发机制。
实现方式
被观察者,商品类
import java.math.BigDecimal;
import java.util.Observable;
public class Product extends Observable {
protected String name;
protected BigDecimal price;
public Product(String name, BigDecimal price) {
super();
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public BigDecimal getPrice() {
return price;
}
/**
* 商品名称变更
* @param name 商品名称
*/
public void setName(String name){
this.name = name;
setChanged();
//通知观察者
notifyObservers(name);
}
/**
* 价格变更
* @param price 商品价格
*/
public void setPrice(BigDecimal price){
this.price = price;
setChanged();
//通知观察者
notifyObservers(price);
}
}
观察者类,名称观察者
import java.util.Observable;
import java.util.Observer;
public class NameObserver implements Observer {
/**
* 更新
*/
@Override
public void update(Observable observable, Object arg) {
if(arg instanceof String){
String name = (String) arg;
System.out.println("您关注的商品名称发生了变化,最新的商品名称是"+name);
}
}
}
观察者类,价格观察者
import java.math.BigDecimal;
import java.util.Observable;
import java.util.Observer;
public class PriceObserver implements Observer{
/**
* 更新
* @param obj 更新对象
*/
@Override
public void update(Observable observable, Object arg) {
if(arg instanceof BigDecimal){
BigDecimal price = (BigDecimal)arg;
System.out.println("您关注的商品价格发生了变化,最新的商品价格是:"+price);
}
}
}
客户端调用
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
Product product = new Product("iphone 6",new BigDecimal(8999));
System.out.println("您关注的商品的名称是:"+product.getName()+",价格是:"+product.getPrice());
//创建观察者
NameObserver nameObserver = new NameObserver();
PriceObserver priceObserver = new PriceObserver();
//加入观察者
product.addObserver(nameObserver);
product.addObserver(priceObserver);
//产生变化,通知观察者
product.setName("iphone 7");
product.setPrice(new BigDecimal(12999));
}
}
扩展与思考
- 观察者模式与之前学习的Javascript回调函数类似,JQuery中有
jQuery.Callbacks(flags)
,都有一套触发机制 - JDK中提供了
java.util.Observable
实现类和java.util.Observer
的接口,所以实际中我们可以直接使用,而不用自己去写重复代码和建立对应的接口。 - 异步处理问题,一般观察者的模式默认是顺序执行的,一旦中间观察者卡壳,会影响整体的执行效率,需要考虑异步。
- 广播链问题,比如数据库的触发器,表A的触发器,修改表B字段,表B的触发器触发修改表C...也就是一个观察者可以有双重身份,即是观察者也是被观察者。
- 观察者模式可以考虑使用RxJava框架,来解决3和4的问题,还对接口柯西化处理,运用链式编程风格,使用方便。