-
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é)果

代理模式一般分為普通代理、強(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é)果

僅僅修改了構(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();
}
}

總結(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é)果

代理模式的優(yōu)點(diǎn)
1.職責(zé)清晰
2.擴(kuò)展和智能