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

  • Provide a surrogate or placeholder for another object to control access to it.(為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。)

    代理模式也叫委托模式。許多其他的模式,如狀態(tài)模式、策略模式、訪問者模式本質(zhì)上是在更特殊的場(chǎng)合采用了委托模式,而且在日常的應(yīng)用中,代理模式可以提供非常好的訪問控制。
    一個(gè)代理類可以代理多個(gè)被委托者或被代理者,因此一個(gè)代理類具體代理哪個(gè)真實(shí)主題
    角色,是由場(chǎng)景類決定的。當(dāng)然,最簡(jiǎn)單的情況就是一個(gè)主題類和一個(gè)代理類,這是最簡(jiǎn)潔的代理模式。在通常情況下,一個(gè)接口只需要一個(gè)代理類就可以了,具體代理哪個(gè)實(shí)現(xiàn)類由高層模塊來決定,也就是在代理類的構(gòu)造函數(shù)中傳遞被代理
先看一個(gè)簡(jiǎn)單的代理模式例子

蘋果手機(jī)生產(chǎn)就是一個(gè)很真實(shí)的代理模式,蘋果自己不生產(chǎn)手機(jī),它的手機(jī)基本都是通過代理公司來生產(chǎn)的。
我們現(xiàn)在模擬生產(chǎn)手機(jī)這個(gè)場(chǎng)景來讓大家對(duì)代理模式的初識(shí)

生產(chǎn)手機(jī)步驟 Phone

/**
 * @author shuliangzhao
 * @Title: Phone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:04
 */
public interface Phone {

    //安裝屏幕
    void assemblyScreen();
    //安裝電池
    void battery();
    //軟件測(cè)試
    void software();
}

ApplePhone

/**
 * @author shuliangzhao
 * @Title: ApplePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:07
 */
public class ApplePhone implements Phone {

    @Override
    public void assemblyScreen() {
        System.out.println("安裝屏幕!");
    }

    @Override
    public void battery() {
        System.out.println("安裝電池!");
    }

    @Override
    public void software() {
        System.out.println("調(diào)試軟件!");
    }
}

代理類PorxyPhoneFactory

/**
 * @author shuliangzhao
 * @Title: PorxyPhoneFactory
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:15
 */
public class PorxyPhoneFactory implements Phone {

    private Phone phone = null;

    public PorxyPhoneFactory(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void assemblyScreen() {
        this.phone.assemblyScreen();
    }

    @Override
    public void battery() {
        this.phone.battery();
    }

    @Override
    public void software() {
        this.phone.software();
    }
}

客戶端

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:16
 */
public class Client {

    public static void main(String[] args) {
        Phone phone = new ApplePhone();
        Phone proxyPhone = new PorxyPhoneFactory(phone);
        proxyPhone.assemblyScreen();
        proxyPhone.battery();
        proxyPhone.software();
    }
}

運(yùn)行結(jié)果


image.png
代理模式一般分為普通代理、強(qiáng)制代理、動(dòng)態(tài)代理

1.普通代理

普通代理就是我們要知道代理的存在,也就是類似的PorxyPhoneFactory 這個(gè)類的存在,然后才能訪問。普通代理只能訪問代理角色,而不能訪問真實(shí)角色,蘋果不能自己生產(chǎn)手機(jī),場(chǎng)景類不能直接new ApplePhone,,它必須由PorxyPhoneFactory來進(jìn)行
模擬場(chǎng)景。
Phone

/**
 * @author shuliangzhao
 * @Title: Phone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:04
 */
public interface Phone {

    //安裝屏幕
    void assemblyScreen();
    //安裝電池
    void battery();
    //軟件測(cè)試
    void software();
}

OrdianyApplePhone

/**
 * @author shuliangzhao
 * @Title: ApplePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:28
 */
public class OrdianyApplePhone implements Phone {

    private String name = "";

    public OrdianyApplePhone(Phone phone, String name) throws Exception {
        if (phone == null) {
            throw new Exception("不能生產(chǎn)手機(jī)");
        }else {
            this.name = name;
        }
    }

    @Override
    public void assemblyScreen() {
        System.out.println(this.name + "組裝屏幕");
    }

    @Override
    public void battery() {
        System.out.println(this.name + "組裝電池");
    }

    @Override
    public void software() {
        System.out.println(this.name + "調(diào)試軟件");
    }
}

OrdianyProxyPhoneFactory

/**
 * @author shuliangzhao
 * @Title: OrdianyProxyPhoneFactory
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:33
 */
public class OrdianyProxyPhoneFactory implements Phone {

    private Phone phone = null;

    public OrdianyProxyPhoneFactory(String name) {
        try {
            phone = new OrdianyApplePhone(this,name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void assemblyScreen() {
        phone.assemblyScreen();
    }

    @Override
    public void battery() {
        phone.battery();
    }

    @Override
    public void software() {
        phone.software();
    }
}

客戶端 Client

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:36
 */
public class Client {

    public static void main(String[] args) {
        Phone phone = new OrdianyProxyPhoneFactory("富士康");
        phone.assemblyScreen();
        phone.battery();
        phone.software();
    }
}

運(yùn)行結(jié)果


image.png

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

2.強(qiáng)制代理

強(qiáng)制代理比較另類,一般思維都是通過代理找真實(shí)類,但是強(qiáng)制代理是通過真實(shí)角色找代理類,否則你不能訪問。這好比你給你老板打電話,你老板說我很忙,你先找下我的秘書。本來你想繞過秘書找老板,但是返回的還是秘書,這就是強(qiáng)制代理。
ForcePhone

/**
 * @author shuliangzhao
 * @Title: ForcePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:50
 */
public interface ForcePhone {
    //安裝屏幕
    void assemblyScreen();
    //安裝電池
    void battery();
    //軟件測(cè)試
    void software();
    //每個(gè)工廠都可以找自己代理
    ForcePhone getPorxy();
}

ForceApplePhone

public class ForceApplePhone implements ForcePhone{

    private String name = "";

    private ForcePhone forcePhone = null;

    public ForceApplePhone(String name) {
        this.name = name;
    }

    @Override
    public void assemblyScreen() {
        if (this.isProxy()) {
            System.out.println(name + "組裝電腦");
        }else {
            System.out.println("請(qǐng)使用代理指定服務(wù)!");
        }
    }

    @Override
    public void battery() {
        if (this.isProxy()) {
            System.out.println(name + "組裝電池");
        }else {
            System.out.println("請(qǐng)使用代理指定服務(wù)!");
        }
    }

    @Override
    public void software() {
        if (this.isProxy()) {
            System.out.println(name + "調(diào)試軟件");
        }else {
            System.out.println("請(qǐng)使用代理指定服務(wù)!");
        }
    }

    //找到自己代理
    @Override
    public ForcePhone getPorxy() {
        this.forcePhone = new ForceProxyPhoneFactory(this);
        return this;
    }

    //增加了一個(gè)私有方法,檢查是否是自己指定的代理,是指定的代理則允許訪問,否則不
    //允許訪問。
    private boolean isProxy(){
        if(this.forcePhone == null){
            return false;
        }else{
            return true;
        }
    }
}

ForceProxyPhoneFactory

public class ForceProxyPhoneFactory implements ForcePhone {

    private ForcePhone forcePhone;
    public ForceProxyPhoneFactory(ForcePhone forcePhone) {
        this.forcePhone = forcePhone;
    }

    @Override
    public void assemblyScreen() {
        forcePhone.assemblyScreen();
    }

    @Override
    public void battery() {
        forcePhone.battery();
    }

    @Override
    public void software() {
        forcePhone.software();
    }

    @Override
    public ForcePhone getPorxy() {
        return this;
    }
}

客戶端 Client

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:58
 */
public class Client {

    public static void main(String[] args) {
        //場(chǎng)景一
        System.out.println("=================場(chǎng)景一=============");
        ForcePhone forcePhone = new ForceApplePhone("富士康");
        ForcePhone proxyForcePhone = new ForceProxyPhoneFactory(forcePhone);
        proxyForcePhone.assemblyScreen();
        proxyForcePhone.battery();
        proxyForcePhone.software();
        System.out.println("++++++++++++++++++++++++++++++++++");
        //場(chǎng)景二
        System.out.println("=================場(chǎng)景二=============");
        ForcePhone forcePhone1 = new ForceApplePhone("富士康");
        forcePhone1.assemblyScreen();
        forcePhone1.battery();
        forcePhone1.software();
        System.out.println("+++++++++++++++++++++++++++++++++++");
        //場(chǎng)景三
        System.out.println("=================場(chǎng)景三=============");
        ForcePhone forcePhone2 = new ForceApplePhone("富士康");
        ForcePhone porxy = forcePhone2.getPorxy();
        porxy.assemblyScreen();
        porxy.battery();
        porxy.software();
    }
}
image.png

總結(jié):
場(chǎng)景一出現(xiàn)原因:不能訪問原因,你new自己出來當(dāng)然真實(shí)對(duì)象不認(rèn),就好比老板已經(jīng)告訴你了去找秘書,你不能隨便找一個(gè)秘書??!
場(chǎng)景二出現(xiàn)原因:你必須通過代理來訪問,直接訪問不行。

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

動(dòng)態(tài)代理是在實(shí)現(xiàn)階段不用關(guān)心代理誰,而在運(yùn)行階段才指定代理哪一個(gè)對(duì)象。AOP的核心機(jī)制就是動(dòng)態(tài)代理。主要實(shí)現(xiàn)jdk中的InvocationHandler接口
DynamicPhone

/**
 * @author shuliangzhao
 * @Title: Phone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:04
 */
public interface DynamicPhone {

    //安裝屏幕
    void assemblyScreen();
    //安裝電池
    void battery();
    //軟件測(cè)試
    void software();
}

DynamicApplePhone

/**
 * @author shuliangzhao
 * @Title: ApplePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:07
 */
public class DynamicApplePhone implements DynamicPhone {

    private String name;
    public DynamicApplePhone(String name) {
        this.name = name;
    }

    @Override
    public void assemblyScreen() {
        System.out.println(name+"安裝屏幕!");
    }

    @Override
    public void battery() {
        System.out.println(name+"安裝電池!");
    }

    @Override
    public void software() {
        System.out.println(name+"調(diào)試軟件!");
    }
}

PhoneHandler

/**
 * @author shuliangzhao
 * @Title: PhoneHandler
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/31 0:13
 */
public class PhoneHandler implements InvocationHandler {

    //被代理的實(shí)例
    private Object obj = null;
    //我要代理誰
    public PhoneHandler(Object obj){
        this.obj = obj;
    }

    //調(diào)用被代理的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(this.obj, args);
        //return invoke;
    }
}

客戶端

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/31 0:16
 */
public class Client {
    public static void main(String[] args) {
        DynamicPhone dynamicPhone = new DynamicApplePhone("富士康");
        InvocationHandler phoneHandler = new PhoneHandler(dynamicPhone);
        ClassLoader classLoader = dynamicPhone.getClass().getClassLoader();
        DynamicPhone o = (DynamicPhone) Proxy.newProxyInstance(classLoader, dynamicPhone.getClass().getInterfaces(), phoneHandler);
        o.assemblyScreen();
        o.battery();
        o.software();
    }
}

運(yùn)行結(jié)果


image.png

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

1.職責(zé)清晰
2.擴(kuò)展和智能

最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

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