定义
- Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问)
- 代理设计模式通常有三个角色
- Subject抽象主题角色:抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。
- RealSubject具体角色:也叫做被委托角色、被代理角色。是业务逻辑具体的执行者。
- Proxy代理主题角色:也叫做委托类、代理类。他负责对真实角色的应用,把所有抽象主题类的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。
- 代理模式也叫做委托模式,它是一种基本设计技巧,其他许多模式,如状态模式、策略模式、访问者模式本质上是更特殊场合采用了委托模式
优点
- 职责清晰:真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后的代理完成一件事务,附带的结果就是编程简洁清晰。
- 高扩展性:具体主题角色是随时都会发生变化的,只要它实现了接口,不管如何变化。代理类完全可以在不做任何修改的情况下使用。
- 智能化:如Mybatis自动将表单元素映射到对象上。
使用场景
代码
通用类图
静态代理通用类图
动态代理通用类图
静态代理
静态代理是相对来说比较简单的代理,优点是逻辑简单
类图
代码
代理接口
1 2 3 4 5
| package com.pattern.proxy.staticproxy;
public interface Subject { void request(); }
|
具体被代理的对象(实现代理接口)
1 2 3 4 5 6 7 8 9 10
| package com.pattern.proxy.staticproxy;
public class RealSubject implements Subject {
@Override public void request() { System.out.println("执行了被代理对象的方法"); } }
|
用于代理的对象(实现代理接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.pattern.proxy.staticproxy;
public class Proxy implements Subject { Subject subject = null; public Proxy(){ this.subject = new Proxy(); } public Proxy(Subject subject){ this.subject = subject; } private void before(){ System.out.println("执行了前置方法"); } private void after(){ System.out.println("执行了后置方法"); } @Override public void request() { this.before(); this.subject.request(); this.after(); } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.pattern;
import com.pattern.proxy.normal.Proxy; import com.pattern.proxy.normal.RealSubject; import com.pattern.proxy.normal.Subject;
import org.junit.Test;
public class ProxyTest { @Test public void StaticProxyTest(){ Subject subject = new RealSubject(); Subject proxy = new Proxy(subject); proxy.request(); } }
|
结果
普通代理
普通代理要求客户端只能访问代理角色,而不能访问真实角色。他和静态代理基本相同,只是在静态代理的基础上屏蔽了对高层真实角色。
为方便理解,这里使用游戏代练的场景举例。
类图
代码
代理接口
1 2 3 4 5 6 7 8
| package com.pattern.proxy.normal;
public interface IGamePlayer { void playGame(); void login(); void logout(); }
|
具体被代理的对象(实现代理接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.pattern.proxy.normal;
public class RealGamePlayer implements IGamePlayer { String username; String account; String password; public RealGamePlayer(ProxyGamePlayer proxyGamePlayer,String username, String account, String password) throws Exception{ if(proxyGamePlayer == null){ throw new Exception("无法创建对象"); } else { this.username = username; this.account = account; this.password = password; } } @Override public void playGame() { System.out.println("用户:" + username + "正在打游戏"); }
@Override public void login() { System.out.println("帐号为:" + account + ",密码为:" + password + ",登录成功"); }
@Override public void logout() { System.out.println("用户:" + username + "登出"); } }
|
用于代理的对象(实现代理接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.pattern.proxy.normal;
public class ProxyGamePlayer implements IGamePlayer { private RealGamePlayer realGamePlayer; public ProxyGamePlayer(String name, String account, String password){ try { realGamePlayer = new RealGamePlayer(this, name, account, password); } catch (Exception e) { e.printStackTrace(); } } @Override public void playGame() { this.realGamePlayer.playGame(); }
@Override public void login() { this.realGamePlayer.login(); }
@Override public void logout() { this.realGamePlayer.logout();
} }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.pattern;
import com.pattern.proxy.normal.ProxyGamePlayer; import com.pattern.proxy.normal.RealGamePlayer; import com.pattern.proxy.staticproxy.Proxy; import com.pattern.proxy.staticproxy.RealSubject; import com.pattern.proxy.staticproxy.Subject;
import org.junit.Test;
public class ProxyTest { @Test public void NormalProxyTest(){ System.out.println("--------------试图直接创建一个对象--------------"); try { RealGamePlayer realGamePlayer = new RealGamePlayer(null, "张三","admin","admin"); } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("--------------使用代理创建一个对象--------------"); ProxyGamePlayer proxy = new ProxyGamePlayer("张三","admin","admin"); proxy.login(); proxy.playGame(); proxy.logout();
} }
|
运行结果
强制代理
强制代理在代理模式的大家族里比较另类,因为代理模式正常的思维是通过代理找到真实的角色,而强制代理则是必须要”强制”。必须通过真实角色查找到代理角色,否则你不能访问。简单来说就是高层模块new了一个真实角色的对象,返回的却是代理角色。
为了方便理解,使用用户售后的场景。用户买的XX牌电脑出故障了,找XX牌公司进行售后,但是实际售后的并不是商家本身,而是产品的代工厂。
类图
代码
代理接口(接口)
1 2 3 4 5 6 7 8 9 10 11
| package com.pattern.proxy.force;
public interface IComputerAfterSale { void afterSale(); IComputerAfterSale getProxy(); }
|
被代理对象(实现代理接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.pattern.proxy.force;
public class ComputerCompany implements IComputerAfterSale { private IComputerAfterSale oem; @Override public IComputerAfterSale getProxy(){ this.oem = new ComputerOEM(this); return oem; } private boolean isProxy(){ return (oem == null); }
@Override public void afterSale() { if(this.isProxy()){ System.out.println("售后由代工厂提供"); } else { System.out.println("厂家完成了电脑的售后"); } } }
|
用于代理的对象(实现代理接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.pattern.proxy.force;
public class ComputerOEM implements IComputerAfterSale{ private IComputerAfterSale computerCompany; public ComputerOEM(IComputerAfterSale computerCompany){ this.computerCompany = computerCompany; } @Override public void afterSale() { this.computerCompany.afterSale(); } @Override public IComputerAfterSale getProxy() { return this; } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package com.pattern;
import com.pattern.proxy.force.ComputerCompany; import com.pattern.proxy.force.ComputerOEM; import com.pattern.proxy.force.IComputerAfterSale; import com.pattern.proxy.normal.ProxyGamePlayer; import com.pattern.proxy.normal.RealGamePlayer; import com.pattern.proxy.staticproxy.Proxy; import com.pattern.proxy.staticproxy.RealSubject; import com.pattern.proxy.staticproxy.Subject;
import org.junit.Test;
public class ProxyTest { @Test public void ForceProxyTest(){ System.out.println("-------------直接找厂家售后(直接访问真实角色)-------------"); ComputerCompany computerCompany = new ComputerCompany(); computerCompany.afterSale(); System.out.println("-------------直接找代工厂售后(直接访问代理角色)-------------"); ComputerOEM oem = new ComputerOEM(computerCompany); oem.afterSale(); System.out.println("-------------强制代理-------------"); ComputerCompany intel = new ComputerCompany(); IComputerAfterSale proxy = intel.getProxy(); proxy.afterSale(); } }
|
运行结果
动态代理
动态代理在实现阶段不用关心代理谁,而是在运行阶段才指定代理哪一个对象。动态代理根据被代理的接口生成所有的方法。给定一个接口,动态代理会宣称”已经实现了接口下所有的方法”。所有被代理的方法都由InvocationHandler接管实际的处理操作。
类图
代码
代理接口(接口)
1 2 3 4 5 6
| package com.pattern.proxy.dynamic;
public interface IProxySubject { void doSomething(); }
|
具体被代理的类(实现代理接口)
1 2 3 4 5 6 7 8 9
| package com.pattern.proxy.dynamic;
public class ProxySubjectImpl implements IProxySubject{ @Override public void doSomething() { System.out.println("执行了逻辑事务"); } }
|
Handler(实现InvocationHandler接口):具体的方法交由此类处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.pattern.proxy.dynamic;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class SubjectInvocationHandler implements InvocationHandler { private IProxySubject proxySubject; public SubjectInvocationHandler(IProxySubject proxySubject){ this.proxySubject = proxySubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object value = null; this.before(); value = method.invoke(proxySubject,args); this.after(); return value; } private void before(){ System.out.println("对业务进行权限验证"); } private void after(){ System.out.println("记录日志"); } }
|
创建代理对象的工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.pattern.proxy.dynamic;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy;
public class DynamicUtils { public static Object newProxyInstance(Object target, InvocationHandler invocationHandler) { ClassLoader classLoader = target.getClass().getClassLoader(); Class<?>[] interfaces = target.getClass().getInterfaces(); return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.pattern;
import com.pattern.proxy.dynamic.DynamicUtils; import com.pattern.proxy.dynamic.IProxySubject; import com.pattern.proxy.dynamic.ProxySubjectImpl; import com.pattern.proxy.dynamic.SubjectInvocationHandler; import com.pattern.proxy.force.ComputerCompany; import com.pattern.proxy.force.ComputerOEM; import com.pattern.proxy.force.IComputerAfterSale; import com.pattern.proxy.normal.ProxyGamePlayer; import com.pattern.proxy.normal.RealGamePlayer; import com.pattern.proxy.staticproxy.Proxy; import com.pattern.proxy.staticproxy.RealSubject; import com.pattern.proxy.staticproxy.Subject;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
public class ProxyTest { @Test public void DynamicProxyTest(){ IProxySubject subject = new ProxySubjectImpl(); InvocationHandler invocationHandler = new SubjectInvocationHandler(subject); IProxySubject proxy = (IProxySubject) DynamicUtils.newProxyInstance(subject, invocationHandler); proxy.doSomething();
} }
|
运行结果
注意
- 普通代理模式的约束问题,尽量通过团队内编程规范类约束,
- 代理是有个性的,代理类不仅仅可以实现主题接口也可以实现其他的接口完成不同的任务,代理的目的是在目标对象方法的基础上做增强。这种增强的本质就是对目标对象的方法进行拦截和过滤
- 代理类不仅仅可以有自己的方法,通常情况下代理的职责并不单一,可以组合其他的真实角色,也可以实现自己的职责
- 动态代理和静态代理的区别:动态代理主要的意图是解决”审计”问题,也就是切面编程,在不改变已有的代码结构的情况下增强或控制对象的行为。
- 动态代理的首要条件是:被代理类必须实现一个接口,但现在有例如CGLIB可以不需要接口也能实现动态代理。