【菜鳥學Java】12:代理模式——靜態代理怎麼玩?
什麼是靜態代理?
周所周知,常用的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"));}}
小結一下:
對於靜態代理,有其好處,但是其缺點也是顯而易見的。靜態代理中的代理類和委託類實現了相同的介面,代理類通過委託類實現了相同的方法。這樣就出現了大量的代碼重複。如果介面新增加一個方法,除了所有的實作類別需要實現這個方法外,所有的代理類也需要實現該方法,這就給代碼的維護增加了很大的麻煩。
其次,靜態代理模式只服務於一種類型的對象,如果我們要增加一個業務類,那麼就必須相應的增加一個代理類,這樣如果我們的程式規模非常大,使用靜態代理就是一個十分不划算的選擇了。那麼如何解決這個問題呢?且聽下回分解。