設(shè)計(jì)模式——代理模式

代理模式(Proxy Pattern)是一個(gè)使用率非常高的模式。
定義:Provide a surrogate or placeholder for another object to control access to it. (為其對(duì)象提供一種代理以控制這個(gè)對(duì)象的訪問(wèn))

代理模式的通用類圖

代理模式也叫委托模式,它是一項(xiàng)基本的設(shè)計(jì)技巧。許多其他的模式,如狀態(tài)模式、策略模式、訪問(wèn)者模式本質(zhì)上是在更特殊的場(chǎng)合采用了委托模式,而且在日常應(yīng)用中,代理模式可以提供非常好的訪問(wèn)控制。

三個(gè)角色的定義

  • Subject抽象主題角色

抽象主題類可以是抽象類也可以是接口,是一個(gè)最普通的業(yè)務(wù)類型定義,無(wú)特殊要求。

  • RealSubject具體的主題角色

也叫做被委托的角色、被代理的角色。是業(yè)務(wù)邏輯的具體執(zhí)行者。

  • Proxy代理主題角色

也叫委托類、代理類。它負(fù)責(zé)對(duì)真實(shí)角色的應(yīng)用,把所以抽象主題定義的方法限制委托給真實(shí)主題角色實(shí)現(xiàn),并且在真實(shí)主題角色處理完畢前后做預(yù)處理和善后工作。

抽象主題類:

public interface Subject {
    //定義一個(gè)方法
    public void request();
}

真實(shí)主題類:

public class RealSubject implements Subject {
    //實(shí)現(xiàn)方法
    @Override
    public void request() {
        //業(yè)務(wù)邏輯處理
    }
}

代理類:

public class Proxy implements Subject {
    //要代理哪個(gè)實(shí)現(xiàn)類
    private Subject subject = null;
    //默認(rèn)被代理者
    public Proxy() {
        this.subject = new Proxy();
    }
    //通過(guò)構(gòu)造函數(shù)傳遞代理者
    public Proxy(Object object){
    }
    //實(shí)現(xiàn)接口中的方法
    @Override
    public void request() {
        this.before();
        this.request();
        this.after();
    }
    //預(yù)處理
    private void before() {
        
    }
    //善后處理
    private void after() {

    }
}

一個(gè)代理類可以代理多個(gè)被委托者或者被代理者,因此一個(gè)代理者具體代理哪個(gè)真實(shí)主題角色,是由場(chǎng)景類決定的。在通常情況下,一個(gè)接口只需要一個(gè)代理類就可以了,具體代理哪個(gè)實(shí)現(xiàn)類由高層模塊決定,也就是在代理類的構(gòu)造函數(shù)中傳遞被代理者。


代理模式的應(yīng)用

代理模式的優(yōu)點(diǎn)

  • 職責(zé)清晰
    真實(shí)的角色就是實(shí)現(xiàn)實(shí)際的業(yè)務(wù)邏輯,不用關(guān)心其他非本職責(zé)的事務(wù),通過(guò)后期的代理完成一件事物,附帶的結(jié)果就是編程簡(jiǎn)潔清晰。
  • 高擴(kuò)展性
    具體主題角色是隨時(shí)會(huì)發(fā)生變化的,只要它實(shí)現(xiàn)了接口,無(wú)論它如何變化都逃不脫接口,那我們的代理類完全就可以在不做任何修改的情況下使用。
  • 智能化
    動(dòng)態(tài)代理的典型應(yīng)用

代理模式的使用場(chǎng)景

類似現(xiàn)實(shí)生活中買房子的中介,打官司的律師。你不想?yún)⑴c中間過(guò)程的是是非非。減輕用戶的負(fù)擔(dān)。代理模式使用場(chǎng)景非常多。最典型的是Spring AOP中的動(dòng)態(tài)代理。


代理模式的擴(kuò)展

普通代理

普通代理就是我們要知道代理的存在,也就是類似GamePlayerProxy這個(gè)代理類的存在,然后才能訪問(wèn)。
普通代理的要求就是客戶端只能訪問(wèn)代理角色,而不能訪問(wèn)真實(shí)角色。以游戲代練為例子,

普通代理類圖.jpg

游戲者接口

public interface IGamePlayer {
    //登陸
    public void login(String user,String password);
    //殺怪
    public void killBoss();
    //升級(jí)
    public void upgrade();
}

GamePlayer的構(gòu)造函數(shù)增加了_gamePlayer參數(shù),而代理角色則只要傳入代理者名字即可,而不需要說(shuō)是替哪個(gè)對(duì)象做代理

普通代理的游戲者

public class GamePlayer implements IGamePlayer {
    private String name="";
    //構(gòu)造函數(shù)限制誰(shuí)能創(chuàng)建對(duì)象,并同時(shí)傳遞姓名
    public GamePlayer(IGamePlayer _gamePlayer,String _name) throws Exception {
        if(_gamePlayer==null){
            throw new Exception("不能創(chuàng)建真實(shí)角色");
        }else{
            this.name = _name;
        }
    }
    @Override
    public void login(String user, String password) {
        System.out.println("登錄名為"+user+"的用戶"+this.name+" 登錄成功");
    }
    @Override
    public void killBoss() {
        System.out.println(this.name+"在擊殺小怪");
    }
    @Override
    public void upgrade() {
        System.out.println(this.name+"又升一級(jí)");
    }
}

在構(gòu)造函數(shù)中,傳來(lái)進(jìn)來(lái)一個(gè)IGaemPlayer對(duì)象,檢查誰(shuí)能創(chuàng)建真實(shí)的角色,或者做出別的限制。

普通代理的代理者

public class GamePlayProxy implements IGamePlayer {
    private IGamePlayer gamePlayer = null;
    //通過(guò)構(gòu)造函數(shù)傳遞要對(duì)誰(shuí)進(jìn)行代練
    public GamePlayProxy(String name) {
        try {
            gamePlayer = new GamePlayer(this, name);
        } catch (Exception e) {
            //異常處理
        }
    }
    @Override
    public void login(String user, String password) {
        this.gamePlayer.login(user, password);
    }
    @Override
    public void killBoss() {
        this.gamePlayer.killBoss();
    }
    @Override
    public void upgrade() {
        this.gamePlayer.upgrade();
    }
}

僅僅修改了構(gòu)造函數(shù),傳遞進(jìn)來(lái)一個(gè)代理者名稱,即可進(jìn)行代理,在這種改造下,系統(tǒng)更加簡(jiǎn)潔,調(diào)用者只知道代理的存在就行,不用知道代理了誰(shuí)。

普通代理的場(chǎng)景

public class Client {
    public static void main(String[] args) {
        //定義一個(gè)代練者
        IGamePlayer proxy = new GamePlayProxy("代練玩家");
        //開(kāi)始游戲 ,記下時(shí)間
        System.out.println("開(kāi)始時(shí)間:2018-8-1 13:10");
        proxy.login("Yang", "123123");
        //開(kāi)始?xì)⒐?        proxy.killBoss();
        //開(kāi)始升級(jí)
        proxy.upgrade();
        //記錄結(jié)束游戲時(shí)間
        System.out.println("結(jié)束時(shí)間:2018-8-1 15:10");
    }
}

結(jié)果:

開(kāi)始時(shí)間:2018-8-1 13:10
登錄名為Yang的用戶代練玩家 登錄成功
代練玩家在擊殺小怪
代練玩家又升一級(jí)
結(jié)束時(shí)間:2018-8-1 15:10

在該模式下,調(diào)用者只知道代理而不知道真實(shí)的角色是誰(shuí),屏蔽了真實(shí)角色的變更對(duì)高層模塊的影響,真實(shí)的主題角色想怎么修改都可以,對(duì)高層次的模塊沒(méi)有任何的影響,只要你實(shí)現(xiàn)了接口所對(duì)應(yīng)的方法,該模式非常適合對(duì)擴(kuò)展性要求較高的場(chǎng)合。

強(qiáng)制代理

強(qiáng)制代理是要“強(qiáng)制”,必須通過(guò)真實(shí)角色查找到代理角色,否則不能進(jìn)行訪問(wèn)。無(wú)論是通過(guò)代理類還是直接new一個(gè)主題角色類,都不能訪問(wèn),只有通過(guò)真實(shí)角色指定的代理類才能訪問(wèn),也就是說(shuō)由真實(shí)的角色管理代理角色。例如你和一個(gè)明星比較熟,你直接找明星幫忙要見(jiàn)導(dǎo)演,但是明星說(shuō)她比較忙,讓你找她的經(jīng)紀(jì)人。你本來(lái)想繞過(guò)她的代理,誰(shuí)知道她返回的還是她的代理,這就是強(qiáng)制代理。你可以不知道代理的存在,但是你的所作所為還是需要代理為你提供服務(wù)。

強(qiáng)制代理類圖.jpg

在接口上增加了一個(gè)getProxy()方法,真實(shí)角色GamePlayer可以指定一個(gè)自己的代理,除了代理外誰(shuí)都不能訪問(wèn)。

強(qiáng)制代理的接口

public interface IGamePlayer {
    //登陸
    public void login(String user,String password);
    //殺怪
    public void killBoss();
    //升級(jí)
    public void upgrade();
    //每個(gè)人都可以找自己的代理
    public IGamePlayer getProxy();
}

強(qiáng)制代理的真實(shí)角色

public class GamePlayer implements IGamePlayer{
    private String name="";
    //自己代理是
    private IGamePlayer proxy =null;
    public GamePlayer(String _name){
        this.name =_name;
    }
    //找到自己的代理
    @Override
    public IGamePlayer getProxy() {
        this.proxy = new GamePlayerProxy(this);
        return this.proxy;
    }
    //登錄
    @Override
    public void login(String user, String password) {
        if(this.isProxy()){
            System.out.println("登錄名為"+user+"的用戶"+this.name+" 登錄成功");
        }else{
            System.out.println("請(qǐng)使用指定代理進(jìn)行訪問(wèn)");
        }
    }
    //殺怪
    @Override
    public void killBoss() {
        if(this.isProxy()){
            System.out.println(this.name+"擊殺小怪");
        }else{
            System.out.println("請(qǐng)使用指定代理進(jìn)行訪問(wèn)");
        }
    }
    //升級(jí)
    @Override
    public void upgrade() {
        if(this.isProxy()){
            System.out.println(this.name+"又升一級(jí)");
        }else{
            System.out.println("請(qǐng)使用指定代理進(jìn)行訪問(wèn)");
        }
    }
    //校驗(yàn)是否是代理訪問(wèn)
    private boolean isProxy() {
        if(this.proxy == null){
            return false;
        }else{
            return true;
        }
    }
}

強(qiáng)制代理的代理角色

public class GamePlayerProxy implements IGamePlayer {
    private IGamePlayer gamePlayer = null;
    //構(gòu)造函數(shù)傳遞用戶名
    public GamePlayerProxy(IGamePlayer _gamePlayer){
        this.gamePlayer = _gamePlayer;
    }
    @Override
    public void login(String user, String password) {
        this.gamePlayer.login(user, password);
    }

    @Override
    public void killBoss() {
        this.gamePlayer.killBoss();
    }

    @Override
    public void upgrade() {
        this.gamePlayer.upgrade();
    }
    //代理的代理暫時(shí)沒(méi)有,就是自己
    @Override
    public IGamePlayer getProxy() {
        return this;
    }
}

強(qiáng)制代理的場(chǎng)景

public class Client {
    public static void main(String[] args) {
        //定義一個(gè)真實(shí)角色
        IGamePlayer player = new GamePlayer("張三");
        //獲得指定的代理
        IGamePlayer proxy = player.getProxy();
        //開(kāi)始游戲
        System.out.println("開(kāi)始時(shí)間:2018-8-1 13:10");
        proxy.login("yang", "123123");
        //開(kāi)始?xì)⒐?        proxy.killBoss();
        //開(kāi)始升級(jí)
        proxy.upgrade();
        //記錄結(jié)束游戲時(shí)間
        System.out.println("結(jié)束時(shí)間:2018-8-1 15:10");
    }
}

結(jié)果:

開(kāi)始時(shí)間:2018-8-1 13:10
登錄名為yang的用戶張三 登錄成功
張三擊殺小怪
張三又升一級(jí)
結(jié)束時(shí)間:2018-8-1 15:10

強(qiáng)制代理的概念就是要從真實(shí)的角色查找到代理角色,不允許直接訪問(wèn)真實(shí)角色。高層模塊只要調(diào)用getProxy()就可以訪問(wèn)真實(shí)角色的所以方法,它根本不需要產(chǎn)生一個(gè)代理出來(lái),代理的管理已經(jīng)由真實(shí)角色自己完成。

代理的有自己的個(gè)性

一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,完成不同任務(wù)的整合。也就是說(shuō)代理類不僅僅可以實(shí)現(xiàn)主題接口,也可以實(shí)現(xiàn)其他接口完成不同的任務(wù),而且代理的目的是在目標(biāo)對(duì)象方法的基礎(chǔ)上作增強(qiáng),這種增強(qiáng)的本質(zhì)通常就是對(duì)目標(biāo)對(duì)象的方法進(jìn)行攔截合過(guò)濾。


動(dòng)態(tài)代理

動(dòng)態(tài)代理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容