装饰器模式注重扩展已有的功能。
对于 装饰器模式 的使用场景,以及优缺点等说明,请参考 菜鸟教程|装饰器模式 ,这边文章里面已经说明的非常详细和清楚了。
假设我们存在一个已有功能:PaymentService
及其对应的实现PaymentServiceImpl
。
这个是已经存在的借口:
PaymentService.java
public interface PaymentService {
GatewayResponse collectMoney(Payment payment);
}
这个是已经存在的实现类:
PaymentServiceImpl.java
public class PaymentServiceImpl implements PaymentService {
GatewayService gatewayService;
@Override
public GatewayResponse collectMoney(Payment payment) {
return gatewayService.sale(payment);
}
}
这个是已经存在的调用类:
Main.java
public class Main {
public static void main(String[] args) {
PaymentService paymentService = new PaymentServiceImpl();
Payment p = new Payment() {};
paymentService.collectMoney(p);
}
}
当我感觉生活如此美好,可以领工资的时候,突然发现payment
这么重要的业务竟然没有任何的监控,这个怎么能忍!!!于是,按照常规,我打算这样修改代码:
PaymentServiceImpl.java
public class PaymentServiceImpl implements PaymentService {
GatewayService gatewayService;
LogService logService;
@Override
public GatewayResponse collectMoney(Payment payment) {
long start = System.currentTimeMillis(); // new code
logService.log("payment.count", String.valueOf(1)); // new code
GatewayResponse gr = gatewayService.sale(payment);
long end = System.currentTimeMillis(); // new code
logService.log("payment.cost", String.valueOf((end - start))); // new code
logService.log("payment.count", String.valueOf(-1)); // new code
return gr;
}
}
嗯~~~
新增加了五行代码来监控每个payment
的持续时间已经对payment的个数统计。不过这五行代码和payment
的业务本身一毛钱关系都没有,加到这里面真的是奇丑无比。而且现在是增加两个统计指标,以后要增加更多的指标,还得回来修改这个类。我们时刻要牢记什么是开闭原则:对扩展是开放的,对于修改是关闭的。
是时候展示装饰器模式真正的实力了。
通过需求,我们抽象出来日志的两个统计指标:1. 持续时间(duration);2. 计数器(counter)。这两个统计指标未来还可能改变,但是PaymentService
的实现是不变的(起码暂时是不变的)。这样我们可以抽象出来两个独立的装饰器:PSDurationDecorator
和 PSCounterDecorator
。
PSDurationDecorator.java
// only focus on duration
public class PSDurationDecorator implements PaymentService {
private LogService logService;
private PaymentService paymentService;
public PSDurationDecorator(PaymentService paymentService) {
this.paymentService = paymentService;
}
@Override
public GatewayResponse collectMoney(Payment payment) {
long start = System.currentTimeMillis();
GatewayResponse gr = paymentService.collectMoney(payment);
long end = System.currentTimeMillis();
logService.log("payment.cost", String.valueOf((end - start)));
return gr;
}
}
对于调用方,我们只需要修改一行代码就可以了。
Main.java
public class Main {
public static void main(String[] args) {
// only need to change one line on client side
PaymentService paymentService = new PSDurationDecorator(new PaymentServiceImpl());
Payment p = new Payment() {};
paymentService.collectMoney(p);
}
}
PSCounterDecorator
的实现:
PSCounterDecorator.java
public class PSCounterDecorator implements PaymentService {
private LogService logService;
private PaymentService paymentService;
public PSCounterDecorator(PaymentService paymentService) {
this.paymentService = paymentService;
}
@Override
public GatewayResponse collectMoney(Payment payment) {
logService.log("payment.count", String.valueOf(1));
GatewayResponse gr = paymentService.collectMoney(payment);
logService.log("payment.count", String.valueOf(-1));
return gr;
}
}
对于调用方,增加一个新的指标也只需要修改一行代码就可以了。
Main.java
public class Main {
public static void main(String[] args) {
// only need to change one line on client side
PaymentService paymentService = new PSCounterDecorator(new PSDurationDecorator(new PaymentServiceImpl()));
Payment p = new Payment() {};
paymentService.collectMoney(p);
}
}