熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java設計模式之Proxy模式

2013-11-23 19:46:15  來源: Java高級技術 

  為什麼要使用Proxy?

  授權機制 不同級別的用戶對同一對象擁有不同的訪問權利如Jive 論壇系統中就使用Proxy 進行授權機制控制訪問論壇有兩種人:注冊用戶和游客(未注冊用戶)Jive 中就通過類似ForumProxy 這樣的代理來控制這兩種用戶對論壇的訪問權限

  某個客戶端不能直接操作到某個對象但又必須和那個對象有所互動

  舉例兩個具體情況:

  ()如果那個對象是一個是很大的圖片需要花費很長時間才能顯示出來那麼當這個圖片包含在文檔中時使用編輯器或浏覽器打開這個文檔打開文檔必須很迅速不能等待大圖片處理完成這時需要做個圖片Proxy 來代替真正的圖片

  ()如果那個對象在Internet 的某個遠端服務器上直接操作這個對象因為網絡速度原因可能比較慢那我們可以先用Proxy 來代替那個對象

  總之原則是對於開銷很大的對象只有在使用它時才創建這個原則可以為我們節省很多寶貴的Java 內存 所以有些人認為Java 耗費資源內存我以為這和程序編制思路也有一定的關系

  如何使用Proxy?

  以Jive 論壇系統為例訪問論壇系統的用戶有多種類型:注冊普通用戶 論壇管理者 系統管理者 游客注冊普通用戶才能發言;論壇管理者可以管理他被授權的論壇;系統管理者可以管理所有事務等這些權限劃分和管理是使用Proxy 完成的

  Forum 是Jive 的核心接口在Forum 中陳列了有關論壇操作的主要行為如論壇名稱 論壇描述的獲取和修改帖子發表刪除編輯等

  在ForumPermissions 中定義了各種級別權限的用戶:

  public class ForumPermissions implements Cacheable {

  /*** Permission to read object*/

  public static final int READ = ;

  /*** Permission to administer the entire sytem*/

  public static final int SYSTEM_ADMIN = ;

  /*** Permission to administer a particular forum*/

  public static final int FORUM_ADMIN = ;

  /*** Permission to administer a particular user*/

  public static final int USER_ADMIN = ;

  /*** Permission to administer a particular group*/

  public static final int GROUP_ADMIN = ;

  /*** Permission to moderate threads*/

  public static final int MODERATE_THREADS = ;

  /*** Permission to create a new thread*/

  public static final int CREATE_THREAD = ;

  /*** Permission to create a new message*/

  public static final int CREATE_MESSAGE = ;

  /*** Permission to moderate messages*/

  public static final int MODERATE_MESSAGES = ;

  

  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;

  thisauthorization = authorization;

  public ForumProxy(Forum forum Authorization authorization

  ForumPermissions permissions)

  {

  thisforum = forum;

  thisauthorization = authorization;

  thispermissions = permissions;

  }

  

  public void setName(String name) throws UnauthorizedException

  ForumAlreadyExistsException

  {

  //只有是系統或論壇管理者才可以修改名稱

  if (permissionsisSystemOrForumAdmin()) {

  forumsetName(name);

  }

  else {

  throw new UnauthorizedException();

  }

  }

  

  }

  而DbForum 才是接口Forum 的真正實現以修改論壇名稱為例:

  public class DbForum implements Forum Cacheable {

  

  public void setName(String name) throws

  ForumAlreadyExistsException {

  

  thisname = name;

  //這裡真正將新名稱保存到數據庫中

  saveToDb();

  

  }

  

  }

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

  我們已經知道使用Forum 需要通過ForumProxyJive 中創建一個Forum 是使用Factory 模式有一個總的抽象類ForumFactory在這個抽象類中調用ForumFactory 是通過getInstance()方法實現這裡使用了SingletongetInstance()返回的是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)

  {

  thisfactory = factory;

  thisauthorization = authorization;

  thispermissions = permissions;

  }

  public Forum createForum(String name String description)

  throws UnauthorizedException ForumAlreadyExistsException

  {

  //只有系統管理者才可以創建forum

  if (permissionsget(ForumPermissionsSYSTEM_ADMIN)) {

  Forum newForum = factorycreateForum(name description);

  return new ForumProxy(newForum authorization permissions);

  }

  else {

  throw new UnauthorizedException();

  }

  }

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

  注意到這裡有兩個Proxy:ForumProxy 和ForumFactoryProxy 代表兩個不同的職責:使用Forum 和創建Forum;

  至於為什麼將使用對象和創建對象分開這也是為什麼使用Factory 模式的原因所在:是為了封裝 分派;換句話說盡可能功能單一化方便維護修改

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

  比如:我們有一個很大的Collection具體如hashtable有很多客戶端會並發同時訪問它

  其中一個特別的客戶端要進行連續的數據獲取此時要求其他客戶端不能再向hashtable 中增加或刪除 東東

  最直接的解決方案是:使用collection 的lock讓這特別的客戶端獲得這個lock進行連續的數據獲取然後再釋放lock

  public void foFetches(Hashtable ht){

  synchronized(ht){

  //具體的連續數據獲取動作

  }

  }

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

  第二個解決方案是clone 這個Collection然後讓連續的數據獲取針對clone 出來的那個Collection 操作這個方案前提是這個Collection 是可clone 的而且必須有提供深度clone 的方法Hashtable 就提供了對自己的clone 方法但不是Key 和value 對象的clone關於Clone 含義可以參考專門文章

  public void foFetches(Hashtable ht){

  Hashttable newht=(Hashtable)htclone();

  }

  問題又來了由於是針對clone 出來的對象操作如果原來的母體被其他客戶端操作修改了那麼對clone 出來的對象操作就沒有意義了

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

  使用Proxy 實現這個方案這就是copyonwrite 操作


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27422.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.