什麼是代理
代理就是給目標物件一個代理物件,並由代理物件控制目標的引用。
為什麼要使用代理模式
1、通過引入代理物件的方式,可以間接的訪問目標物件,避免直接訪問目標物件給系統帶來不必要的複雜性。
2、通過代理物件可以對原有的業務進行業務增強處理。
舉例:如果我們需要買國外的某一件商品A,這個時候我們一般有兩個途徑要麼直接去國外買,要麼可以找一些代購人員幫我們去購買。在這種情況下,我們由於直接去國外買,實在是太耗軟妹幣,而且還要花時間等等,這個時候我們最優的選擇就是找代購購買,這樣也幫我們省去了很多麻煩的事情。
代理模式類圖
程式碼示例
抽象物件:
public interface ITargetFactoryService {
void sale(String name);
}
目標物件:
@Slf4j
public class TargetFactoryServiceImpl implements ITargetFactoryService {
@Override
public void sale(String name) {
log.info(name+"購買了商品A");
}
}
代理物件:
@Slf4j
public class ProxyImpl implements ITargetFactoryService {
public ITargetFactoryService service;
public ProxyImpl(ITargetFactoryService service){
super();
this.service = service;
}
@Override
public void sale(String name) {
before();
service.sale("代購");
after();
}
/**
* 後置增強
*/
private void after() {
log.info("代購在購買後得到了市場調查結果");
}
/**
* 前置增強
*/
private void before() {
log.info("代購在購買前做了市場調查");
}
}
測試類:
@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class})
public class SpsringJdbcApplication {
public static void main(String[] args) {
TargetFactoryServiceImpl service = new TargetFactoryServiceImpl();
ProxyImpl proxy = new ProxyImpl(service);
proxy.sale("代購");
SpringApplication.run(SpsringJdbcApplication.class, args);
}
}
測試結果:
我們可以在程式碼示例中清晰的看到,在代理類中,代理物件包含了目標物件,並且在業務處理上進行了一定的業務擴充套件,但是卻和目標物件繼承於同一個介面。但是此擴充套件基於Spring AOP來講,以更加專業的叫法為前置增強、後置增強。
此類代理便是我們常說的靜態代理,靜態代理適合在業務比較簡單,實現類少,需求變化不頻繁,但是卻要對原有目標服務物件功能進行擴充套件,並且不去修改原有服務,這個時候我們就可以選擇使用靜態代理。
靜態代理的缺點
如果此時我們業務需要進行擴充套件,我們的代購同學在經過市場調查以後,發現商品B更加受大家歡迎,這個時候我們就需要對自己的業務進行擴充套件了,怎麼擴充套件呢?一起接著往下看。
抽象物件:
public interface ITargetFactoryBService {
void saleB(String name);
}
目標物件:
@Slf4j
public class ITargetFactoryBServiceImpl implements ITargetFactoryBService {
@Override
public void saleB(String name) {
log.info(name + "購買了商品B");
}
}
代理物件:
@Slf4j
public class ProxyTwoImpl implements ITargetFactoryService, ITargetFactoryBService {
public ITargetFactoryService service;
public ITargetFactoryBService bService;
public ProxyTwoImpl(ITargetFactoryService service,ITargetFactoryBService bService){
super();
this.service = service;
this.bService = bService;
}
@Override
public void sale(String name) {
before();
service.sale("代購");
after();
}
@Override
public void saleB(String name) {
before();
bService.saleB("代購");
after();
}
/**
* 後置增強
*/
private void after() {
log.info("代購在購買後得到了市場調查結果");
}
/**
* 前置增強
*/
private void before() {
log.info("代購在購買前做了市場調查");
}
}
測試類:
@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class})
public class SpsringJdbcApplication {
public static void main(String[] args) {
TargetFactoryServiceImpl service = new TargetFactoryServiceImpl();
ITargetFactoryBServiceImpl bService = new ITargetFactoryBServiceImpl();
ProxyTwoImpl proxy2 = new ProxyTwoImpl(service, bService);
proxy2.sale("代購");
proxy2.saleB("代購");
SpringApplication.run(SpsringJdbcApplication.class, args);
}
}
結果:
我們可以看到,在實現業務擴充套件的時候,需要對原有的代理類進行修改,如果後期我們需要擴充套件的業務較多的時候,這個類將變的更加繁雜,大量的繼承以及方法重寫,以至於牽一髮而動全身,所以在這種業務擴充套件性高、業務變化頻繁的情況下我們不建議使用靜態代理。
靜態代理總結:
1、違反Java設計模式開閉原則,即:程式對外擴充套件開放,對修改關閉。當需求進行變更時,我們應該是新增程式碼塊來實現,而不是在原來的程式碼中進行修改實現。
2、擴充套件性很差。
3、可維護性差。
4、程式碼耦合度高。
如果覺著不錯可以關注公眾號:Java禿頭猿,專注於專案實際開發技術分享。