裝飾器模式注重擴展已有的功能。
對于 裝飾器模式 的使用場景,以及優(yōu)缺點等說明,請參考 菜鳥教程|裝飾器模式 ,這邊文章里面已經(jīng)說明的非常詳細和清楚了。
假設(shè)我們存在一個已有功能:PaymentService及其對應(yīng)的實現(xiàn)PaymentServiceImpl。
這個是已經(jīng)存在的借口:
PaymentService.java
public interface PaymentService {
GatewayResponse collectMoney(Payment payment);
}
這個是已經(jīng)存在的實現(xiàn)類:
PaymentServiceImpl.java
public class PaymentServiceImpl implements PaymentService {
GatewayService gatewayService;
@Override
public GatewayResponse collectMoney(Payment payment) {
return gatewayService.sale(payment);
}
}
這個是已經(jīng)存在的調(diào)用類:
Main.java
public class Main {
public static void main(String[] args) {
PaymentService paymentService = new PaymentServiceImpl();
Payment p = new Payment() {};
paymentService.collectMoney(p);
}
}
當我感覺生活如此美好,可以領(lǐng)工資的時候,突然發(fā)現(xiàn)payment這么重要的業(yè)務(wù)竟然沒有任何的監(jiān)控,這個怎么能忍?。。∮谑?,按照常規(guī),我打算這樣修改代碼:
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;
}
}
嗯~~~
新增加了五行代碼來監(jiān)控每個payment的持續(xù)時間已經(jīng)對payment的個數(shù)統(tǒng)計。不過這五行代碼和payment的業(yè)務(wù)本身一毛錢關(guān)系都沒有,加到這里面真的是奇丑無比。而且現(xiàn)在是增加兩個統(tǒng)計指標,以后要增加更多的指標,還得回來修改這個類。我們時刻要牢記什么是開閉原則:對擴展是開放的,對于修改是關(guān)閉的。
是時候展示裝飾器模式真正的實力了。
通過需求,我們抽象出來日志的兩個統(tǒng)計指標:1. 持續(xù)時間(duration);2. 計數(shù)器(counter)。這兩個統(tǒng)計指標未來還可能改變,但是PaymentService的實現(xiàn)是不變的(起碼暫時是不變的)。這樣我們可以抽象出來兩個獨立的裝飾器: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;
}
}
對于調(diào)用方,我們只需要修改一行代碼就可以了。
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 的實現(xiàn):
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;
}
}
對于調(diào)用方,增加一個新的指標也只需要修改一行代碼就可以了。
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);
}
}