1. 程式人生 > >Java設計模式—代理模式

Java設計模式—代理模式

代理模式

這幾天學了Java設計模式的遠端代理,兩天時間除了上課就是在搞代理模式的遠端代理。這篇文章首先介紹代理模式,下篇文章在介紹遠端代理。

代理模式:
由於某些原因,客戶端不想或不能直接訪問一個物件,此時可以通過一個稱為“代理”的第三者來實現間接訪問。即,給某一個物件提供一個代理,並由代理物件來控制對原物件的訪問。

代理模式的結構:
①Subject(抽象主題角色):他聲明瞭真實主題和代理主題的公共介面,客戶端通常需要針對抽象主題角色來進行程式設計。
②Proxy(代理主題角色):他包含了對真實主題的引用,從而可以任何時間操作真實主題。通常,在代理主題角色中還要進行其他的操作,而不僅僅是呼叫真實主題的操作。因此,在代理主題角色中,往往還添加了新的方法。
③RealSubject(真實主題角色):他定義了代理角色所代表的真實物件,客戶端可以通過呼叫代理主題角色間接的呼叫真實主題角色中定義的操作。
結構圖如圖:在這裡插入圖片描述

例如:向原有資訊查詢功能的系統中增加身份驗證和日誌記錄功能。

/**
 * @description:定義了代理物件和真實物件的公共介面doSearch 
 */
public interface Searcher {
    public String doSearch(String userId,String keyword);
    class Tester{
        public static void main(String args[]){
            Searcher searcher = new ProxySearcher();
            searcher.doSearch("楊過","玉女心經");
        }
    }
}
/**
 * @description:新增加的身份驗證功能
 */
public class AccessValidator {
    public boolean validate(String userId){
        System.out.println("在資料庫中驗證使用者" + userId + "是否為合法使用者?");
        if (userId.equals("楊過")){
            System.out.println(userId + "登入成功");
            return true;
        }else {
            System.out.println(userId + "登入失敗");
            return false;
        }
    }
}
/**
 * @description:新增加的日誌記錄功能
 */
public class Logger {
    public void log(String userId){
        System.out.println("更新資料庫,使用者 " + userId + "查詢次數加1!");
    }
}
/**
 * @description:真實物件實現了公共介面,實現了公共方法
 */
public class RealSearcher implements Searcher{
    @Override
    public String doSearch(String userID,String keyword){
        System.out.println("使用者:" + userID + "使用關鍵詞" + keyword + "查詢商務資訊!");
        return "返回具體內容";
    }
}

/**
 * @description:代理物件實現了Serach介面,幷包含一個真是物件的引用,還有包含有其他的方法
 *                 最後將其他方法耦合到公共介面方法中,拓展了工作介面中的方法.
 */
public class ProxySearcher implements Searcher {
    private RealSearcher realSearcher = new RealSearcher();
    private AccessValidator accessValidator;
    private Logger logger;

    @Override
    public String doSearch(String userId, String keyword) {
        if (this.validate(userId)){
            String result = realSearcher.doSearch(userId,keyword);
            this.log(userId);
            return result;
        }else {
            return null;
        }
    }

    public boolean validate(String userId){
        accessValidator = new AccessValidator();
        return accessValidator.validate(userId);
    }

    public void log(String userId){
        logger = new Logger();
        logger.log(userId);
    }
}

執行公共介面中的內部類,執行main方法,可以看到main方法使用了公共介面程式設計方法,並呼叫代理ProxySearcher()。

/**
 * @description:定義了代理物件和真實物件的公共介面doSearch
 */
public interface Searcher {
    public String doSearch(String userId,String keyword);

    class Tester{
        public static void main(String args[]){
            Searcher searcher = new ProxySearcher();
            searcher.doSearch("楊過","玉女心經");
        }
    }
}/*
在資料庫中驗證使用者楊過是否為合法使用者?
楊過登入成功
使用者:楊過使用關鍵詞玉女心經查詢商務資訊!
更新資料庫,使用者 楊過查詢次數加1!
*/

通過XML配置檔案,生成代理例項物件

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<classname>net.fuqian.learn.java.大話設計模式.代理模式.簡單代理模式.ProxySearcher</classname>  //中間那部分為package包名
</configuration>
/**
 * @description:XML工具類獲取例項物件
 */
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;

public class XMLUtil {
    public static Object getBean(){
        try{
            //建立DOM文件物件
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document document = db.parse(new File("src//net//fuqian//learn//java//大話設計模式//代理模式//簡單代理模式//config.xml"));

            //獲取包含類名的文字結點
            NodeList n1 = document.getElementsByTagName("classname");  //getElementsByTagName 返回指定標籤的內容
            Node classNode = n1.item(0).getFirstChild();
            String cName = classNode.getNodeValue();

            //通過類名生成例項物件並將其返回
            Class c = Class.forName(cName);//Class.forName(String classname)生成指定類的class的物件
            Object object = c.newInstance(); //呼叫class物件.newInstance建立一個類的物件
            return object;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    static class Tester{
        public static void main(String args[]){
            Searcher searcher;
            searcher = (Searcher)XMLUtil.getBean();
            String result = searcher.doSearch("楊過","玉女心經");
        }
    }
}

呼叫靜態的內部類Tester中的main方法執行,結果和上面一樣。可以使用XML配置檔案中的引數作為方法呼叫的引數。因此,可以在不更換客戶端程式碼的情況下,通過更換方法的引數,來改變效果,這在策略模式,工廠模式裡更有效

代理模式就是這麼簡單。下面一篇文章介紹遠端代理,跑步回來更新。