什麼是靜態代理?
周所周知,常用的23種設計模式中,有一個代理模式(Proxy Pattern)。它的定義如下:
為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。
代理模式的思想是為了提供額外的處理或者不同的操作而在實際對象與調用者之間插入一個代理對象。這些額外的操作通常需要與實際對象進行通信。
那麼靜態代理又是什麼鬼呢?所謂靜態就是指,在程序運行前代理類和委托類的對應關系就已經確定了,或者說運行前代理類的字節碼文件就有了。
為何用代理模式?
代理模式主要有三個組成部分:
抽象角色:通過接口或者抽象類聲明真是角色實現的業務方法。
代理角色:實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並且可以附加自己的操作。
真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色調用。
具體的關系我從網上找了一張圖,幫助大家理解:
采用代理模式來開發程序的話,我們的業務類只需要關注自己本身的業務邏輯就行了,其他的什麼日志,權限控制等輔助功能,就不用再管了,交給代理類去完成就可以了。這樣保證了業務類的高復用性。
如何用靜態代理?
這裡我們使用Java寫一個簡單的demo,來說明如何使用靜態代理。大致需求是一個用戶管理的業務類需要添加日志打印功能,如何做呢?方案一,直接將日志打印的代碼寫到用戶管理的業務邏輯實現類裡面的方法中;方案二,使用靜態代理,將日志打印的代碼加到代理類的方法中。在示例代碼中,兩種方式都有體現。
用戶管理接口
public interface UserManager { public void addUser(String userId, String userName); public void delUser(String userId); public void modifyUser(String userId, String userName); public String findUser(String userId); }
用戶管理實現類
public class UserManagerImpl implements UserManager { public void addUser(String userId, String userName) { //直接在業務實現類的方法中添加打印日志的代碼 //System.out.println("start-->>addUser() userId-->>" + userId); try { System.out.println("UserManagerImpl.addUser() userId-->>" + userId); //System.out.println("success-->>addUser()"); }catch(Exception e) { e.printStackTrace(); //System.out.println("error-->>addUser()"); throw new RuntimeException(); } } public void delUser(String userId) { System.out.println("UserManagerImpl.delUser() userId-->>" + userId); } public String findUser(String userId) { System.out.println("UserManagerImpl.findUser() userId-->>" + userId); return "查詢成功,找到用戶張三"; } public void modifyUser(String userId, String userName) { System.out.println("UserManagerImpl.modifyUser() userId-->>" + userId); } }
用戶管理代理類
public class UserManagerImplProxy implements UserManager { //添加真是對象的引用 private UserManager userManager; //通過構造方法將被代理的對象傳入代理類對象 public UserManagerImplProxy(UserManager userManager) { this.userManager = userManager; } public void addUser(String userId, String userName) { try { //為核心業務方法添加打印日志的功能 System.out.println("開始添加用戶,調用方法:addUser() 用戶ID:userId-->>" + userId); userManager.addUser(userId, userName); System.out.println("添加用戶成功!"); }catch(Exception e) { e.printStackTrace(); System.out.println("添加用戶失敗!請聯系管理員……"); } } public void delUser(String userId) { userManager.delUser(userId); } public String findUser(String userId) { return userManager.findUser(userId) ; } public void modifyUser(String userId, String userName) { userManager.modifyUser(userId, userName); } }
客戶端
public class Client { public static void main(String[] args) { //UserManager userManager = new UserManagerImpl(); UserManager userManager = new UserManagerImplProxy(new UserManagerImpl()); userManager.addUser("0001", "張三"); System.out.println(userManager.findUser("0001")); } }
小結一下:
對於靜態代理,有其好處,但是其缺點也是顯而易見的。靜態代理中的代理類和委托類實現了相同的接口,代理類通過委托類實現了相同的方法。這樣就出現了大量的代碼重復。如果接口新增加一個方法,除了所有的實現類需要實現這個方法外,所有的代理類也需要實現該方法,這就給代碼的維護增加了很大的麻煩。
其次,靜態代理模式只服務於一種類型的對象,如果我們要增加一個業務類,那麼就必須相應的增加一個代理類,這樣如果我們的程序規模非常大,使用靜態代理就是一個十分不劃算的選擇了。那麼如何解決這個問題呢?且聽下回分解。