-
Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)
代理模式也叫委托模式。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。
一个代理类可以代理多个被委托者或被代理者,因此一个代理类具体代理哪个真实主题
角色,是由场景类决定的。当然,最简单的情况就是一个主题类和一个代理类,这是最简洁的代理模式。在通常情况下,一个接口只需要一个代理类就可以了,具体代理哪个实现类由高层模块来决定,也就是在代理类的构造函数中传递被代理
先看一个简单的代理模式例子
苹果手机生产就是一个很真实的代理模式,苹果自己不生产手机,它的手机基本都是通过代理公司来生产的。
我们现在模拟生产手机这个场景来让大家对代理模式的初识
生产手机步骤 Phone
/**
* @author shuliangzhao
* @Title: Phone
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/30 23:04
*/
public interface Phone {
//安装屏幕
void assemblyScreen();
//安装电池
void battery();
//软件测试
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("调试软件!");
}
}
代理类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();
}
}
运行结果
代理模式一般分为普通代理、强制代理、动态代理
1.普通代理
普通代理就是我们要知道代理的存在,也就是类似的PorxyPhoneFactory 这个类的存在,然后才能访问。普通代理只能访问代理角色,而不能访问真实角色,苹果不能自己生产手机,场景类不能直接new ApplePhone,,它必须由PorxyPhoneFactory来进行
模拟场景。
Phone
/**
* @author shuliangzhao
* @Title: Phone
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/30 23:04
*/
public interface Phone {
//安装屏幕
void assemblyScreen();
//安装电池
void battery();
//软件测试
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("不能生产手机");
}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 + "调试软件");
}
}
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();
}
}
运行结果
仅仅修改了构造函数,传递进来一个代理者名称,即可进行代理,在这种改造下,系统
更加简洁了,调用者只知道代理存在就可以,不用知道代理了谁。
2.强制代理
强制代理比较另类,一般思维都是通过代理找真实类,但是强制代理是通过真实角色找代理类,否则你不能访问。这好比你给你老板打电话,你老板说我很忙,你先找下我的秘书。本来你想绕过秘书找老板,但是返回的还是秘书,这就是强制代理。
ForcePhone
/**
* @author shuliangzhao
* @Title: ForcePhone
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/30 23:50
*/
public interface ForcePhone {
//安装屏幕
void assemblyScreen();
//安装电池
void battery();
//软件测试
void software();
//每个工厂都可以找自己代理
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("请使用代理指定服务!");
}
}
@Override
public void battery() {
if (this.isProxy()) {
System.out.println(name + "组装电池");
}else {
System.out.println("请使用代理指定服务!");
}
}
@Override
public void software() {
if (this.isProxy()) {
System.out.println(name + "调试软件");
}else {
System.out.println("请使用代理指定服务!");
}
}
//找到自己代理
@Override
public ForcePhone getPorxy() {
this.forcePhone = new ForceProxyPhoneFactory(this);
return this;
}
//增加了一个私有方法,检查是否是自己指定的代理,是指定的代理则允许访问,否则不
//允许访问。
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) {
//场景一
System.out.println("=================场景一=============");
ForcePhone forcePhone = new ForceApplePhone("富士康");
ForcePhone proxyForcePhone = new ForceProxyPhoneFactory(forcePhone);
proxyForcePhone.assemblyScreen();
proxyForcePhone.battery();
proxyForcePhone.software();
System.out.println("++++++++++++++++++++++++++++++++++");
//场景二
System.out.println("=================场景二=============");
ForcePhone forcePhone1 = new ForceApplePhone("富士康");
forcePhone1.assemblyScreen();
forcePhone1.battery();
forcePhone1.software();
System.out.println("+++++++++++++++++++++++++++++++++++");
//场景三
System.out.println("=================场景三=============");
ForcePhone forcePhone2 = new ForceApplePhone("富士康");
ForcePhone porxy = forcePhone2.getPorxy();
porxy.assemblyScreen();
porxy.battery();
porxy.software();
}
}
总结:
场景一出现原因:不能访问原因,你new自己出来当然真实对象不认,就好比老板已经告诉你了去找秘书,你不能随便找一个秘书啊!
场景二出现原因:你必须通过代理来访问,直接访问不行。
2.动态代理
动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。AOP的核心机制就是动态代理。主要实现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();
//软件测试
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+"调试软件!");
}
}
PhoneHandler
/**
* @author shuliangzhao
* @Title: PhoneHandler
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/31 0:13
*/
public class PhoneHandler implements InvocationHandler {
//被代理的实例
private Object obj = null;
//我要代理谁
public PhoneHandler(Object obj){
this.obj = obj;
}
//调用被代理的方法
@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();
}
}
运行结果
代理模式的优点
1.职责清晰
2.扩展和智能