一、什么是观察者模式?
观察者模式是软件设计模式的一种,又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
二、使用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
三、设计模式的实现
Java的API中已经为我们提供了Observer模式的实现。具体由java.util.Observable类和java.util.Observer接口完成。
前者有两个重要的方法:
- setChanged:设置内部状态为已改变
- notifyObservers(Object obj):通知观察者所发生的改变,参数obj是一些改变的信息
后者有一个核心方法:
- update(Objectobj):相应被观察者的改变,其中obj就是被观察者传递过来的信息,该方法会在notifyObservers被调用时自动调用。
下面是Observer模式的实现过程:
-
创建一个被观察者,继承java.util.Observable
-
创建一个观察者,实现java.util.Observer接口
-
注册观察者,调用addObserver(Observer observer)
-
在被观察者改变对象内部状态的地方,调用setChanged()方法,然后调用notifyObservers(Object)方法,通知被观察者
-
在观察者的update(Object)方法中,对改变做出响应。
四、示例
模拟水果商告知小贩A、小贩B水果采购价发生变更
/**
* @date: 2021/9/23 15:17
* @author: wangjw
* @Description:被观察者 水果商的水果单价
*/
public class MyObservable extends Observable {
private String fruitName;//水果名称
private float price;//单价
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return "MyObservable{" +
"fruitName='" + fruitName + '\'' +
", price='" + price + '\'' +
'}';
}
/**
* 添加观察者
* @param sub
*/
public void addServer(MyObserver sub){
this.addObserver(sub);
}
/**
* 删除观察者
* @param sub
*/
public void removeServer(MyObserver sub){
this.deleteObserver(sub);
}
public void changePrice(String fruitName,float price){
this.price = price;
this.fruitName = fruitName;
this.changed();
}
public void changed(){
this.setChanged();
this.notifyObservers();
}
}
/**
* @date: 2021/9/23 15:20
* @author: wangjw
* @Description:观察者抽象类
*/
public abstract class MyObserver implements Observer {
}
/**
* @date: 2021/9/23 15:18
* @author: wangjw
* @Description:观察者实例 小贩A
*/
public class Example_A extends MyObserver {
private final float profit = 1.1f;//小贩A的利润
DecimalFormat df = new DecimalFormat("#0.0");
public Example_A() {
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof MyObservable){
MyObservable observable = (MyObservable) o;
System.out.println("小贩A收到了"
+observable.getFruitName()+
"涨价的消息,现采购价变为" +
observable.getPrice()+
"元每斤,小贩A的"+
observable.getFruitName()+
"售价变为"+df.format(observable.getPrice() + this.profit));
}
}
}
/**
* @date: 2021/9/23 16:42
* @author: wangjw
* @Description:观察者实例 小贩B
*/
public class Example_B extends MyObserver {
private final float profit = 0.8f;//小贩B的利润
DecimalFormat df = new DecimalFormat("#0.0");
public Example_B() {
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof MyObservable){
MyObservable observable = (MyObservable) o;
System.out.println("小贩B收到了"
+observable.getFruitName()+
"涨价的消息,现采购价变为" +
observable.getPrice()+
"元每斤,小贩B的"+
observable.getFruitName()+
"售价变为"+df.format(observable.getPrice() + this.profit));
}
}
}
public static void main(String[] args) throws Exception{
MyObservable observable = new MyObservable();
observable.addServer(new Example_A());
observable.addServer(new Example_B());
observable.changePrice("苹果",9.9f);
}
输出结果