2.7.观察者模式
观察者模式又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
JDK中的使用
- java.util.Observer
- java.util.Observable
代码实现
水果店员没卖出一个订单的水果 老板会关心每种水果卖出了多少 老板娘会关心一共卖出了多少钱
@Getter
public enum Fruit {
APPLE("苹果", new BigDecimal("2")),
ORANGE("桔子", new BigDecimal("1.5")),
GRAPE("葡萄", new BigDecimal("3")),
PLUM("李子", new BigDecimal("6.5"));
private String name;
private BigDecimal unitPrice;
Fruit(String name, BigDecimal unitPrice){
this.name = name;
this.unitPrice = unitPrice;
}
}
@Data
@AllArgsConstructor
public class Order {
private Fruit type;
private BigDecimal weight;
}
public class FruitStoreAssistant extends Observable {
public FruitStoreAssistant(Observer ...observers){
super();
if(observers != null && observers.length > 0){
for(Observer observer : observers){
super.addObserver(observer);
}
}
}
/**
* 贩卖水果
* @param order 水果订单
*/
public void sell(Order order){
super.setChanged();
super.notifyObservers(order);
}
}
@Getter
public class FruitsStoreBoss implements Observer {
private Map<Fruit, BigDecimal> statistics = new HashMap<>();
private BigDecimal total = new BigDecimal("0");
public FruitsStoreBoss(){
Fruit []fruits = Fruit.values();
for(Fruit fruit : fruits){
statistics.put(fruit, new BigDecimal("0"));
}
}
@Override
public void update(Observable o, Object arg) {
if(arg instanceof Order){
this.account((Order) arg);
}
}
private void account(Order order){
Fruit fruit = order.getType();
BigDecimal current = this.statistics.get(fruit);
this.statistics.put(fruit, current.add(order.getWeight()));
this.total = this.total.add(order.getWeight());
}
}
@Getter
public class FruitsStoreLandlady implements Observer {
private Map<Fruit, BigDecimal> statistics = new HashMap<>();
private BigDecimal total = new BigDecimal("0");
public FruitsStoreLandlady(){
Fruit []fruits = Fruit.values();
for(Fruit fruit : fruits){
statistics.put(fruit, new BigDecimal("0"));
}
}
@Override
public void update(Observable o, Object arg) {
if(arg instanceof Order){
this.account((Order) arg);
}
}
private void account(Order order){
Fruit fruit = order.getType();
BigDecimal current = this.statistics.get(fruit);
BigDecimal orderTotal = fruit.getUnitPrice().multiply(order.getWeight());
this.statistics.put(fruit, current.add(orderTotal));
this.total = this.total.add(orderTotal);
}
}
单元测试
class FruitStoreSpec extends Specification {
def fruitStoreEach() {
given:
def boss = new FruitsStoreBoss()
def landlady = new FruitsStoreLandlady()
def assistant = new FruitStoreAssistant(boss, landlady)
when:
assistant.sell(new Order(fruit, weight))
then:
landlady.getTotal() == totalAmount
boss.getTotal() == totalWeight
where:
fruit | weight || totalAmount || totalWeight
Fruit.PLUM | 8.7 || Fruit.PLUM.unitPrice * 8.7 || 8.7
Fruit.APPLE | 1 || Fruit.APPLE.unitPrice * 1 || 1
Fruit.GRAPE | 2.3 || Fruit.GRAPE.unitPrice * 2.3 || 2.3
Fruit.ORANGE | 2.5 || Fruit.ORANGE.unitPrice * 2.5 || 2.5
}
}