代理模式(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í)角色。以游戲代練為例子,

游戲者接口
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ù)。

在接口上增加了一個(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ò)濾。