代理模式:通过代理类对目标类进行包装。
代理类、目标类要具有一样的功能,实现共同的接口。用户只能看到代理类,实际上是通过代理类与目标类进行交互。
静态代理模式:每个代理类只代理一个目标类
实现相同的接口,代理类中持有一个目标类的对象的引用,通过构造器为目标类赋值。
案例如下:
Demo类:
public class Demo {
public static void main(String[] args){
//静态代理,FactoryProxy只能单独代理FactoryImpl类
FactoryProxy factoryProxy = new FactoryProxy(new FactoryImpl());
System.out.println(factoryProxy.produc());
}
}
共同实现的接口:
public interface Factory {
String produc();
}
public class FactoryImpl implements Factory {
@Override
public String produc() {
String str = "生产的字符串";
return str;
}
}
public class FactoryProxy implements Factory {
//代理类中持有的目标类对象
private FactoryImpl factoryImpl;
//通过构造方法新建目标类对象
public FactoryProxy(FactoryImpl factoryImpl) {
this.factoryImpl = factoryImpl;
}
@Override
public String produc() {
String str = "经过代理后 " + factoryImpl.produc();
return str;
}
}
静态代理程序运行结果:
经过代理后 生产的字符串
静态代理模式每次增加新的目标类都必须增加配套的代理类,当目标类较多时程序会过于复杂,工程量大,此时建议使用动态代理模式。
动态代理模式:动态代理多个类
使用ProxyHandler类动态代理多个类。ProxyHandler类持有一个Object对象,通过构造器初始化Object对象。实现了InvocationHandler接口。重写了invoke方法。
案例如下:
Demo类:
import java.lang.reflect.Proxy;
public class Demo {
public static void main(String[] args) {
System.out.println("测试类1:Count接口实现类\n");
CountImpl countImpl = new CountImpl();
ProxyHandler ph = new ProxyHandler(countImpl);
//newProxyInstance返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
/*
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
*/
Count count = (Count) Proxy.newProxyInstance(countImpl.getClass().getClassLoader(),
<span style="white-space:pre"> </span> countImpl.getClass().getInterfaces(),
ph);
//调用add()
int result = count.add(5, 10);
System.out.println("调用add方法结果: "+result);
System.out.println("\n---------------------------------\n");
//调用print()
String result2 = count.print();
System.out.println("调用print方法结果: "+result2);
//测试其他目标类
System.out.println("\n测试类2:GetSet接口实现类\n");
GetSetImpl getsetImpl = new GetSetImpl();
ProxyHandler phGC = new ProxyHandler(getsetImpl);
GetSet getset = (GetSet) Proxy.newProxyInstance(getsetImpl.getClass().getClassLoader(),
getsetImpl.getClass().getInterfaces(),
phGC);
//调用set()
getset.set('X');
System.out.println("\n---------------------------------\n");
//调用get()
char c = getset.get();
System.out.println("Get: "+c);
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ProxyHandler implements InvocationHandler {
//目标类的对象,由于需要所有的类都能用当前的类来代理,所以创建一个Object对象
private Object obj;
//假设代理的是CountImpl,若调用里面的方法。多个方法可以看接口中的方法列表
public ProxyHandler(Object obj) {
this.obj = obj;
}
/**
* 在代理实例上处理方法调用并返回结果。
* proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。
Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。
基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
*
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用的方法: "+method);
System.out.println("方法参数列表: "+Arrays.toString(args));
//调用此方法
Object result = method.invoke(obj, args);
return result;
}
}
测试对象类接口1:
public interface Count {
int add(int a, int b);
String print();
}
测试对象目标类1:
public class CountImpl implements Count{
@Override
public int add(int a, int b){
System.out.println("目标类CountImpl做的工作: a+b");
return a+b;
}
@Override
public String print() {
System.out.println("目标类CountImpl做的工作: print");
return "This is Class CountImpl";
}
}
测试对象类接口2:
public interface GetSet {
char get();
void set(char c);
}
public class GetSetImpl implements GetSet {
private char temp;
@Override
public char get() {
return this.temp;
}
@Override
public void set(char c) {
this.temp = c;
}
}
动态代理程序运行结果:
测试类1:Count接口实现类
调用的方法: public abstract int trends_proxy.Count.add(int,int)
方法参数列表: [5, 10]
目标类CountImpl做的工作: a+b
调用add方法结果: 15
---------------------------------
调用的方法: public abstract java.lang.String trends_proxy.Count.print()
方法参数列表: null
目标类CountImpl做的工作: print
调用print方法结果: This is Class CountImpl
测试类2:GetSet接口实现类
调用的方法: public abstract void trends_proxy.GetSet.set(char)
方法参数列表: [X]
---------------------------------
调用的方法: public abstract char trends_proxy.GetSet.get()
方法参数列表: null
Get: X
当需要增加新的目标类时,只需要添加目标类接口及其实现类,在使用时通过ProxyHandler类代理即可,不需要增加额外的代理类。