為什麼要使用代理模式
Proxy是比較有用途的一種模式,而且變種較多,應用場合覆蓋從小結構到整個系統的大結構,Proxy是代理的意思,我們也許有代理伺服器等概念,代理概念可以解釋為:在出發點到目的地之間有一道中間層,意為代理.
設計模式中定義: 為其他物件提供一種代理以控制對這個物件的訪問.
為什麼要使用Proxy?
1.授權機制 不同級別的使用者對同一物件擁有不同的訪問權利,如Jive論壇系統中,就使用Proxy進行授權機制控制,訪問論壇有兩種人:註冊使用者和遊客(未註冊使用者),Jive中就通過類似ForumProxy這樣的代理來控制這兩種使用者對論壇的訪問許可權.
2.某個客戶端不能直接操作到某個物件,但又必須和那個物件有所互動.
舉例兩個具體情況:
(1)如果那個物件是一個是很大的圖片,需要花費很長時間才能顯示出來,那麼當這個圖片包含在文件中時,使用編輯器或瀏覽器開啟這個文件,開啟文件必須很迅速,不能等待大圖片處理完成,這時需要做個圖片Proxy來代替真正的圖片.
(2)如果那個物件在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 = 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:ForumProxy和ForumFactoryProxy. 代表兩個不同的職責:使用Forum和建立Forum;
至於為什麼將使用物件和建立物件分開,這也是為什麼使用Factory模式的原因所在:是為了"封裝" "分派";換句話說,儘可能功能單一化,方便維護修改.
Jive論壇系統中其他如帖子的建立和使用,都是按照Forum這個思路而來的.
以上我們討論瞭如何使用Proxy進行授權機制的訪問,Proxy還可以對使用者隱藏另外一種稱為copy-on-write的優化方式.拷貝一個龐大而複雜的物件是一個開銷很大的操作,如果拷貝過程中,沒有對原來的物件有所修改,那麼這樣的拷貝開銷就沒有必要.用代理延遲這一拷貝過程.
比如:我們有一個很大的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)ht.clone();
}
問題又來了,由於是針對clone出來的物件操作,如果原來的母體被其他客戶端操作修改了, 那麼對clone出來的物件操作就沒有意義了.
最後解決方案:我們可以等其他客戶端修改完成後再進行clone,也就是說,這個特別的客戶端先通過呼叫一個叫clone的方法來進行一系列資料獲取操作.但實際上沒有真正的進行物件拷貝,直至有其他客戶端修改了這個物件Collection.
使用Proxy實現這個方案.這就是copy-on-write操作.
設計模式中定義: 為其他物件提供一種代理以控制對這個物件的訪問.
為什麼要使用Proxy?
1.授權機制 不同級別的使用者對同一物件擁有不同的訪問權利,如Jive論壇系統中,就使用Proxy進行授權機制控制,訪問論壇有兩種人:註冊使用者和遊客(未註冊使用者),Jive中就通過類似ForumProxy這樣的代理來控制這兩種使用者對論壇的訪問許可權.
2.某個客戶端不能直接操作到某個物件,但又必須和那個物件有所互動.
舉例兩個具體情況:
(1)如果那個物件是一個是很大的圖片,需要花費很長時間才能顯示出來,那麼當這個圖片包含在文件中時,使用編輯器或瀏覽器開啟這個文件,開啟文件必須很迅速,不能等待大圖片處理完成,這時需要做個圖片Proxy來代替真正的圖片.
(2)如果那個物件在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 = 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:ForumProxy和ForumFactoryProxy. 代表兩個不同的職責:使用Forum和建立Forum;
至於為什麼將使用物件和建立物件分開,這也是為什麼使用Factory模式的原因所在:是為了"封裝" "分派";換句話說,儘可能功能單一化,方便維護修改.
Jive論壇系統中其他如帖子的建立和使用,都是按照Forum這個思路而來的.
以上我們討論瞭如何使用Proxy進行授權機制的訪問,Proxy還可以對使用者隱藏另外一種稱為copy-on-write的優化方式.拷貝一個龐大而複雜的物件是一個開銷很大的操作,如果拷貝過程中,沒有對原來的物件有所修改,那麼這樣的拷貝開銷就沒有必要.用代理延遲這一拷貝過程.
比如:我們有一個很大的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)ht.clone();
}
問題又來了,由於是針對clone出來的物件操作,如果原來的母體被其他客戶端操作修改了, 那麼對clone出來的物件操作就沒有意義了.
最後解決方案:我們可以等其他客戶端修改完成後再進行clone,也就是說,這個特別的客戶端先通過呼叫一個叫clone的方法來進行一系列資料獲取操作.但實際上沒有真正的進行物件拷貝,直至有其他客戶端修改了這個物件Collection.
使用Proxy實現這個方案.這就是copy-on-write操作.
Proxy應用範圍很廣,現在流行的分佈計算方式RMI和Corba等都是Proxy模式的應用.
轉載來自:http://blog.163.com/love_wangchao/blog/static/21251930820138811412715/
相關文章
- Nginx代理websocket為什麼要這樣做?NginxWeb
- 為什麼爬蟲要選擇住宅代理?爬蟲
- 為什麼要使用代理池?
- 為什麼要虛擬化,為什麼要容器,為什麼要Docker,為什麼要K8S?DockerK8S
- 為什麼要選擇代理來進行抓取?
- 為什麼 JavaScript 要設計原型模式JavaScript原型模式
- 重構模式(二)---- 為什麼要 Refactoring模式
- 什麼是隧道代理 為什麼選隧道代理
- NGINX伺服器有什麼作用?什麼叫反向代理?為什麼要使用反向代理?Nginx伺服器
- 為什麼要使用模組模式?模式
- Smart海外代理-IP為什麼要選擇節點多的代理商?
- 為什麼要removeREM
- 為什麼要敏捷?敏捷
- 為什麼使用 HTTP 爬蟲代理更安全?HTTP爬蟲
- 為什麼Redis叢集要使用反向代理?Redis
- 為什麼要用SOCKS代理?
- 為什麼要用代理和動態代理
- 什麼是設計模式?為什麼要使用設計模式?有什麼好處?設計模式
- 為什麼要code reviewView
- 為什麼要謹慎使用Linux find命令?Linux
- 為什麼說Java中要慎重使用繼承Java繼承
- 為什麼要學習和使用C語言?C語言
- 為什麼要做聚合支付代理?
- GC 為什麼要掛起使用者執行緒? 什麼愁什麼怨?GC執行緒
- 為什麼不建議使用免費的IP代理?
- 為什麼要學習 RustRust
- 為什麼要學習 Julia
- 為什麼要指令重排序?排序
- 為什麼要學習 Vim?
- 為什麼要選擇SQL?SQL
- MySQL為什麼要set namesMySql
- Java 8 動態代理的新技巧(1):為什麼使用動態代理?Java
- 設計師為什麼要學程式設計,開發者為什麼要學設計?程式設計
- 為什麼 JavaScript 的 this 要這麼用?JavaScript
- 小程式代理加盟:這些理由告訴你,為什麼要加盟小程式
- 為什麼前端初學者必須要明白髮布訂閱模式前端模式
- 為什麼使用海外HTTP代理後,網速變得很慢?HTTP
- Python是什麼?為什麼要掌握python?Python