設計模式之Proxy(代理)

理解並使用設計模式 , 能夠培養我們良好的面向物件編程習慣 , 同時在實際應用中 , 可以如魚得水 , 享受遊刃有餘的樂趣。

Proxy 是比較有用途的一種模式 , 而且變種較多 , 應用場合覆蓋從小結構到整個系統的大結構 ,Proxy 是代理的意思 , 我們也許有代理伺服器等概念 , 代理概念可以解釋爲 : 在出發點到目的地之間有一道中間層 , 意爲代理。

設計模式中定義 : 爲其他物件提供一種代理以控制對這個物件的訪問。

爲什麽要使用 Proxy?
1.
授權機制 不同級別的用戶對同一物件擁有不同的訪問權利 ,Jive 論壇系統中 , 就使用 Proxy 進行授權機制控制 , 訪問論壇有兩種人 : 註冊用戶和遊客 ( 未註冊用戶 ),Jive 中就通過類似 ForumProxy 這樣的代理來控制這兩種用戶對論壇的訪問許可權。

2. 某個用戶端不能直接操作到某個物件 , 但又必須和那個物件有所互動。
舉例兩個具體情況
:
(1)
如果那個物件是一個是很大的圖片 , 需要花費很長時間才能顯示出來 , 那麽當這個圖片包含在文檔中時 , 使用編輯器或瀏覽器打開這個文檔 , 打開文檔必須很迅速 , 不能等待大圖片處理完成 , 這時需要做個圖片 Proxy 來代替真正的圖片。

(2)
如果那個物件在 Internet 的某個遠端伺服器上 , 直接操作這個物件因爲網路速度原因可能比較慢 , 那我們可以先用 Proxy 來代替那個物件。

總之原則是 , 對於開銷很大的物件 , 只有在使用它時才創建 , 這個原則可以爲我們節省很多寶貴的 Java 記憶體。 所以 , 有些人認爲 Java 耗費資源記憶體 , 我以爲這和程式編制思路也有一定的關係。

如何使用 Proxy?
Jive論壇系統 爲例 , 訪問論壇系統的用戶有多種類型 : 註冊普通用戶 論壇管理者 系統管理者 遊客 , 註冊普通用戶才能發言 ; 論壇管理者可以管理他被授權的論壇 ; 系統管理者可以管理所有事務等 , 這些許可權劃分和管理是使用 Proxy 完成的。

ForumJive 的核心介面 ,Forum 中陳列了有關論壇操作的主要行爲 , 如論壇名稱 論壇描述的獲取和修改 , 帖子發表刪除編輯等。

ForumPermissions 中定義了各種級別許可權的用戶 :

public class ForumPermissions implements Cacheable {

/**
* Permission to read object.
*/
public static final int READ = 0;

/**
* Permission to administer the entire sytem.
*/
public static final int SYSTEM_ADMIN = 1;

/**
* Permission to administer a particular forum.
*/
public static final int FORUM_ADMIN = 2;

/**
* Permission to administer a particular user.
*/
public static final int USER_ADMIN = 3;

/**
* Permission to administer a particular group.
*/
public static final int GROUP_ADMIN = 4;

/**
* Permission to moderate threads.
*/
public static final int MODERATE_THREADS = 5;

/**
* Permission to create a new thread.
*/
public static final int CREATE_THREAD = 6;

/**
* Permission to create a new message.
*/
public static final int CREATE_MESSAGE = 7;

/**
* Permission to moderate messages.
*/
public static final int MODERATE_MESSAGES = 8;

.....

public boolean isSystemOrForumAdmin() {
   return (values[FORUM_ADMIN] || values[SYSTEM_ADMIN]);
}

.....

}

因此 ,Forum 中各種操作許可權是和 ForumPermissions 定義的用戶級別有關係的 , 作爲介面 Forum 的實現 :ForumProxy 正是將這種對應關係聯繫起來。比如 , 修改 Forum 的名稱 , 只有論壇管理者或系統管理者可以修改 , 代碼如下 :

public class ForumProxy implements Forum {

private ForumPermissions permissions;
private Forum forum;
this.authorization = authorization;

public ForumProxy(Forum forum, Authorization authorization,
ForumPermissions permissions)
{
this.forum = forum;
this.authorization = authorization;
this.permissions = permissions;
}

.....

public void setName(String name) throws UnauthorizedException,
ForumAlreadyExistsException
{
   // 只有是系統或論壇管理者才可以修改名稱
  
if (permissions.isSystemOrForumAdmin()) {
    
forum.setName(name);
  
}
  
else {
    
throw new UnauthorizedException();
   }
}

...

}

DbForum 才是介面 Forum 的真正實現 , 以修改論壇名稱爲例 :

public class DbForum implements Forum, Cacheable {
...

public void setName(String name) throws ForumAlreadyExistsException {

  
....

  
this.name = name;
   // 這裏真正將新名稱保存到資料庫中
   saveToDb();

   ....
}


...

}

凡是涉及到對論壇名稱修改這一事件 , 其他程式都首先得和 ForumProxy 打交道 ,ForumProxy 決定是否有許可權做某一樣事情 ,ForumProxy 是個名副其實的 " 閘道 "," 安全代理系統 "

在平時應用中 , 無可避免總要涉及到系統的授權或安全體系 , 不管你有無意識的使用 Proxy, 實際你已經在使用 Proxy 了。

我們繼續結合 Jive 談入深一點 , 下面要涉及到工廠模式了 , 如果你不瞭解工廠模式 , 請看我的另外一篇文章 :設計模式之 Factory

我們已經知道 , 使用 Forum 需要通過 ForumProxy,Jive 中創建一個 Forum 是使用 Factory 模式 , 有一個總的抽象類別 ForumFactory, 在這個抽象類別中 , 呼叫 ForumFactory 是通過 getInstance() 方法實現 , 這裏使用了 Singleton( 也是設計模式之一 , 由於介紹文章很多 , 我就不寫了 ,看這裏 ),getInstance() 返回的是 ForumFactoryProxy

爲什麽不返回 ForumFactory, 而返回 ForumFactory 的實現 ForumFactoryProxy?
原因是明顯的 , 需要通過代理確定是否有許可權創建 forum

ForumFactoryProxy 中我們看到代碼如下 :

public class ForumFactoryProxy extends ForumFactory {

   protected ForumFactory factory;
  
protected Authorization authorization;
   protected ForumPermissions permissions;

   public ForumFactoryProxy(Authorization authorization, ForumFactory factory,
  
ForumPermissions permissions)
  
{
    
this.factory = factory;
    
this.authorization = authorization;
    
this.permissions = permissions;
   }

   public Forum createForum(String name, String description)
      
throws UnauthorizedException, ForumAlreadyExistsException
  
{
     // 只有系統管理者才可以創建
forum
    
if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {
      
Forum newForum = factory.createForum(name, description);
      
return new ForumProxy(newForum, authorization, permissions);
    
}
    
else {
      
throw new UnauthorizedException();
   }
}

方法 createForum 返回的也是 ForumProxy, Proxy 就象一道牆 , 其他程式只能和 Proxy 交互操作。

注意到這裏有兩個 Proxy:ForumProxyForumFactoryProxy 代表兩個不同的職責 : 使用 Forum 和創建 Forum;
至於爲什麽將使用物件和創建物件分開 , 這也是爲什麽使用 Factory 模式的原因所在 : 是爲了 " 封裝 " " 分派 "; 換句話說 , 盡可能功能單一化 , 方便維護修改。

Jive 論壇系統中其他如帖子的創建和使用 , 都是按照 Forum 這個思路而來的。

以上我們討論了如何使用 Proxy 進行授權機制的訪問 ,Proxy 還可以對用戶隱藏另外一種稱爲 copy-on-write 的優化方式。拷貝一個龐大而複雜的物件是一個開銷很大的操作 , 如果拷貝過程中 , 沒有對原來的物件有所修改 , 那麽這樣的拷貝開銷就沒有必要。用代理延遲這一拷貝過程。

比如 : 我們有一個很大的 Collection, 具體如 hashtable, 有很多用戶端會並發同時訪問它。其中一個特別的用戶端要進行連續的資料獲取 , 此時要求其他用戶端不能再向 hashtable 中增加或刪除 東東。

最直接的解決方案是 : 使用 collectionlock, 讓這特別的用戶端獲得這個 lock, 進行連續的資料獲取 , 然後再釋放 lock
public void foFetches(Hashtable ht){
  
synchronized(ht){
     // 具體的連續資料獲取動作。。
   }

}

但是這一辦法可能鎖住 Collection 會很長時間 , 這段時間 , 其他用戶端就不能訪問該 Collection 了。

第二個解決方案是 clone 這個 Collection, 然後讓連續的資料獲取針對 clone 出來的那個 Collection 操作。這個方案前提是 , 這個 Collection 是可 clone, 而且必須有提供深度 clone 的方法。 Hashtable 就提供了對自己的 clone 方法 , 但不是 Keyvalue 物件的 clone, 關於 Clone 含義可以參考 專門文章
public void foFetches(Hashtable ht){

   Hashttable newht=(Hashtable)ht.clone();

}

問題又來了 , 由於是針對 clone 出來的物件操作 , 如果原來的母體被其他用戶端操作修改了 , 那麽對 clone 出來的物件操作就沒有意義了。

最後解決方案 : 我們可以等其他用戶端修改完成後再進行 clone, 也就是說 , 這個特別的用戶端先通過呼叫一個叫 clone 的方法來進行一系列資料獲取操作。但實際上沒有真正的進行物件拷貝 , 直至有其他用戶端修改了這個物件 Collection

使用 Proxy 實現這個方案。這就是 copy-on-write 操作。

Proxy 應用範圍很廣 , 現在流行的分佈計算方式 RMICorba 等都是 Proxy 模式的應用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值