为什么要使用代理模式?
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
例如:我要买一个电脑,但是我不能没有任何准备工作就去买电脑,比如买点脑之前,必须先准备好钱,找到去商店的地址,然后付钱买电脑,买了电脑之后还应该把电脑拿回家开机。
其中除了买电脑这个核心业务由主类完成,其他的买电脑前和买电脑后的一些操作全部由辅助类来完成。这就是代理设计模式。
代理模式的优点:
(1). 职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务。
(2). 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。(3). 高扩展性。
代理模式的分类:
静态代理:N个接口对应N个真实业务类和N个辅助实现类。
动态代理:N个接口对应N个真实业务类和1个辅助实现类。
一个静态的代理模式应该有以下几部分组成:
一个接口:IObject
一个真实业务类:RealObject
一个辅助实现类:ProxyObject
一个静态代理模式的例子:
接口定义:
public interface IMessage { void msg(); }
真实业务类:
public class RealMessage implements IMessage{ @Override public void msg() { System.out.println("发送消息"); } }
辅助类:
public class ProxyMessage implements IMessage{ private IMessage realMsg; public ProxyMessage(IMessage realMsg) { this.realMsg = realMsg; } @Override public void msg() { this.beforeMsg(); this.realMsg.msg(); this.afterMsg(); } public void beforeMsg() { System.out.println("联网"); } public void afterMsg() { System.out.println("断开连接"); } }
测试:
public class Test { public static void main(String[] args) throws Exception { IMessage proxyMessage = new ProxyMessage(new RealMessage()); proxyMessage.msg(); } }
运行结果:
普通代理模式与通用工厂模式
工厂模式好处:
客户端不需要改动代码,只需要改变传入的参数。将客户端与服务端解耦。
以上其他代码不变,新增Factory类:
import java.lang.reflect.Constructor; /** * 代理模式与工厂模式 */ public class Factory { private Factory() {} /** * 返回一个代理类的对象 * @param proxyClassName * @param realClassName * @return * @throws Exception */ public static <T> T getInstance(String proxyClassName, String realClassName) throws Exception { // 获取辅助类的Class对象 Class<?> proxyCls = Class.forName(proxyClassName); // 获取真实业务类的Class对象 Class<?> realCls = Class.forName(realClassName); // 获取真实业务类对象 T realObj = (T)realCls.newInstance(); // 获取辅助类对象 Constructor proxyConstructor = proxyCls.getConstructor(realCls.getInterfaces()[0]); T t = (T) proxyConstructor.newInstance(realObj); return t; } }
测试类:
public class Test { public static void main(String[] args) throws Exception { IMessage msg = Factory.getInstance("静态代理通用工厂.ProxyMessage", "静态代理通用工厂.RealMessage"); msg.msg(); } }
运行结果:
静态代理的缺点:所有的代理类的代码结构类似,所以代码的冗余度过高。动态代理模式很好的解决了这一缺点
动态代理模式:
当有多个以上代理模式时,由于所有的代理类的结构都是一样的,可以使用一个辅助类来代替所有的辅助类
实现以上需求需要代理类实现InvocationHandler接口
结构如下:
Factory类:用于生产代理类对象和真实业务类对象
ISubject:业务实现接口
Person类:真实业务实现类
ProxyObject类:通用的代理类
Test类:测试类
代理类的代码如下:
class ProxyObject implements InvocationHandler{ private Object realObject; /** * 用于将真实业务类和代理类绑定 * @param realObject * @return */ public Object bind(Object realObject) { this.realObject = realObject; return Proxy.newProxyInstance(realObject.getClass().getClassLoader(), realObject.getClass().getInterfaces(), this); } /** * 两个通用的辅助真实处理业务逻辑的方法。 */ public void beforeHandle() { System.out.println("准备处理业务"); } public void afterHandle() { System.out.println("善后工作"); } /** * 这个方法是自动调用的,当绑定之后调用真实业务逻辑的时候,将会自动调用\ * proxy 在其上调用该方法的代理实例 * method 与代理实例上调用的接口方法相对应的方法实例(真实处理业务的方法) * args method方法传入的参数。 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { beforeHandle(); Object ret = method.invoke(realObject, args); afterHandle(); return ret; } }
工厂类代码如下:
import java.lang.reflect.Method; /** * 工厂 */ public class Factory { private Factory() {} /** * 获取realObject的实例 * @param proxyName 代理类类名称 * @param realName 真实类的名称 * @return * @throws Exception */ public static Object getInstance(String proxyClassName, String realClassName) throws Exception { //获取代理类 Class<?> proxyClass = Class.forName(proxyClassName); //获取真实业务类 Class<?> realClass = Class.forName(realClassName); // 获取代理类bind方法 Method bindMethod = proxyClass.getDeclaredMethod("bind", Object.class); // 返回代理类对象 return bindMethod.invoke(proxyClass.newInstance(), realClass.newInstance()); } }
测试类:
public class Test { public static void main(String[] args) throws Exception { ISubject subject =(ISubject) Factory.getInstance("动态代理.ProxyObject", "动态代理.Person"); subject.eat(); } }
运行结果: