为什么要使用代理模式?
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
例如:我要买一个电脑,但是我不能没有任何准备工作就去买电脑,比如买点脑之前,必须先准备好钱,找到去商店的地址,然后付钱买电脑,买了电脑之后还应该把电脑拿回家开机。
其中除了买电脑这个核心业务由主类完成,其他的买电脑前和买电脑后的一些操作全部由辅助类来完成。这就是代理设计模式。
代理模式的优点:
(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();
}
}
运行结果: