1、定义
代理模式也称为委托模式,为一个对象提供一个代理对象,以此来控制被代理对象的访问,简单来说就是代理对象代替被代理对象来完成一些事情。
代理模式一般分为静态代理和动态代理:
静态代理:代理类在代码编译以前就已经存在。
动态代理:运行时动态的创建代理对象,可以很灵活的代理自己想要代理的对象,通过反射机制来实现。
2、使用场景
当不想直接方位或者访问某个对象存在困难的时候就可以通过代理对象来简介的完成访问。
3、UML类图
4、代码实现
1、静态代理实现
/**
* 租房行为接口
*/
public interface IRent {
void rent();
}
/**
* 租客
*/
public class Renter implements IRent {
@Override
public void rent() {
System.out.println("我要租房子");
}
}
/**
* 中介
*/
public class Agency implements IRent{
private IRent renter;
public Agency(IRent renter) {
this.renter = renter;
}
@Override
public void rent() {
System.out.println("我帮客户租房子");
renter.rent();
//TODO 处理租房的其他逻辑,如查找房源
}
}
public class MainTest {
public static void main(String[] args) {
IRent reenter = new Renter();
IRent agency = new Agency(reenter);
agency.rent();
}
}
2、动态代理实现
/**
* 主题接口
*/
public interface Subject {
void request();
}
/**
* 具体主题类
*/
public class ConcreteSubject implements Subject {
@Override
public void request() {
System.out.println("具体主题类");
}
}
/**
* 动态代理Handler实现InvocationHandler接口,重写invoke方法
*/
public class DynamicHandler implements InvocationHandler {
/**
* 被代理的类,可以代理任意对象
*/
private Object obj;
public DynamicHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//TODO 添加代理对象的逻辑
//通反射的方式来调用被代理对象的方法
return method.invoke(obj, args);
}
}
/**
* 测试
*/
public class MainTest {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
DynamicHandler dynamicHandler = new DynamicHandler(concreteSubject);
Class<?> cls = concreteSubject.getClass();
/**
* 构造一个Subject的代理对象
* 参数:
* 类加载器;
* concreteSubject实现的接口
* 动态代理Handler对象
*/
Subject subjectProxy = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), dynamicHandler);
subjectProxy.request();
}
}
实现动态代理模式涉及到两个关键的类InvocationHandler和Proxy。InvocationHandler是一个接口,里面只有一个invoke方法。
public interface InvocationHandler {
/**
* @param proxy 代理对象
* @param method 被代理对象的Method对象
* @param args 请求方法的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
/**
* @param loader 类加载器
* @param interfaces 被代理对象实现的接口
* @param h 请求处理类,被代理对象的方法调用的会交给InvocationHandler的invoke方法来完成
* @return
*/
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
通过Proxy的newProxyInstance方法动态的生成代理对象,每一个动态代理类都会有一个与之对应的InvocationHandler,动态代理所调用的方法都会交由InvocationHandler的invoke方法去处理,在invoke方法中就可以添加代理代理代理对象的逻辑。
3、Kotlin实现
Kotlin原生代码就支持代理模式,是通过关键字by来实现的。以下是kotlin官方的例子。
interface Base {
fun printMessage()
fun printMessageLine()
}
class BaseImpl(val x: Int) : Base {
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
}
class Derived(b: Base) : Base by b {
override fun printMessage() { print("abc") }
}
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).printMessage()
Derived(b).printMessageLine()
}
output:abc10
5、总结
代理模式应用非常广泛,可以在处理被代理对象的逻辑的同时注入代理对象自己的逻辑。
代码:https://gitee.com/os2chen/DesignPattern
参考:《Head First Design》、《Android源码设计模式解析与实战》