1. 程式人生 > >設計模式的藝術 結構性模式之代理模式

設計模式的藝術 結構性模式之代理模式

前言

現實中有些東西想要但是在別的國家想買但是過去買的成本太大,所以有中介這種行業應運而生,相對於自己去買的話比較便宜,也節省時間,在軟體設計中,也存在著這麼一種模式,客戶端不能直接訪問某個物件,此時可以通過一個稱之為代理的第三章來實現間接訪問,該方案對應的設計模式被稱之為代理模式。

什麼是代理模式 Proxy Pattern

給某個物件提供一個代理,並由代理物件控制對原物件的引用,代理模式是一種物件結構型模式

代理模式的優點

(1)、代理模式1能夠協調呼叫者與被呼叫者,在一定程度上降低了系統的耦合度,滿足迪米特法則

(2)、客戶端可以針對抽象主題角色進行程式設計,增加和更換代理類無須修改原始碼,符合開閉原則,系統具有較好的靈活性和可擴充套件性

(3)、遠端代理為位於兩個不同地址空間物件的訪問提供了一種實現機制,可以將一些消耗資源較多的物件和操作移至效能更好的計算機上,提高系統的整體執行效率

(4)、虛擬代理通過一個消耗資源較少的物件來代表一個消耗資源較多的物件,可以在一定程度上節省系統的執行開銷

(5)、保護代理可以控制對一個物件的訪問許可權,為不同使用者提供不同級別的使用許可權

代理模式的缺點

(1)、由於在客戶端和真實主題之間增加了代理物件,因此有些型別的的代理模式可能會造成請求的處理速度變慢,例如保護代理

(2)、實現代理模式需要額外的工作,有些代理模式的實現非常複雜,例如遠端代理

代理模式的適用場景

代理模式的型別較多,所以可以根據不同的場景去適用

(1)、當客戶端物件需要訪問遠端主機中的物件時,可以使用遠端代理

(2)、當需要用一個消耗資源較少的物件來代表一個消耗資源較多的物件,從而降低系統開銷、縮短執行時間時,可以使用虛擬代理,例如一個物件需要很長時間才能完成載入時

(3)、當需要控制對一個物件的訪問,為不同使用者提供不同級別的訪問許可權時,可以使用保護代理

(4)、當需要為某一個被頻繁訪問的操作結果提供一個臨時儲存空間,以供多個客戶端共享訪問這些結果時,可以使用緩衝代理,通過緩衝代理,系統無須再客戶端每一次訪問時都重新執行操作,只需要從臨時緩衝區獲取操作結果即可。

(5)、當需要為一個物件的訪問提供一些額外操作時,可以使用智慧引用代理。

代理模式的具體實現

目錄結構

抽象主題類

package com.company;

//抽象查詢類:抽象主題類
public interface Searcher {
    public String doSearch(String userId,String keyword);
}

真實主題類

//具體查詢類:真實主題類
public class RealSearcher  {
    //模擬查詢商務資訊
    public String doSearch(String userId,String keyword){
        System.out.println("使用者:"+userId+"使用關鍵詞"+keyword+"查詢商務資訊");
        return  "返回具體內容";
    }
}

代理主題類

//代理查詢類:代理主題類
public class ProxySearcher implements Searcher {
    private RealSearcher realSearcher=new RealSearcher();//維持一個對真實主題的引用
    private AccessValidator validator;
    private Logger logger;
    @Override
    public String doSearch(String userId, String keyword) {
        //如果身份驗證成功,則執行查詢
        if(validate(userId)){
            String result=realSearcher.doSearch(userId,keyword); //呼叫真實主題物件的查詢方法
            this.log(userId);  //記錄查詢日誌
            return  result;  //返回查詢結果
        }else{
            return  null;
        }
    }
    //建立訪問驗證物件並呼叫其validate()方法實現身份驗證
    public boolean validate(String userId){
        validator =new AccessValidator();
        return  validator.validate(userId);
    }
    //建立日誌記錄物件並呼叫其log()方法實現日誌記錄
    public void log(String userId){
        logger=new Logger();
        logger.log(userId);
    }
}

業務類

//日誌記錄類:業務類
public class Logger {
    //模擬實現日誌記錄類
    public void log(String userId){
        System.out.println("更新資料庫,使用者"+userId+"查詢次數加1");
    }
}

身份驗證類

//身份驗證類:業務類
public class AccessValidator {
    //模擬實現登入驗證
    public boolean validate(String userId){
        System.out.println("在資料庫中驗證使用者"+userId+"是否是合法使用者");
        if(userId.equalsIgnoreCase("楊過")){
            System.out.println(userId+"登入成功");
            return  true;
        }else{
            System.out.println(userId+"登入失敗");
            return false;
        }
    }
}

客戶端測試類

public class Client {

    public static void main(String[] args) {
   Searcher searcher;  //針對抽象程式設計,客戶端無須分辨真實主題類和代理類
        searcher=(Searcher) XMLUtil.getBean();
        String result=searcher.doSearch("楊過","御女心經");
    }
}

轉載請註明出處,掌聲送給社會人