代理模式
代理模式用最简单的例子来表示就是你想定制个T恤,但你不认识加工厂,就找了个中介帮你联系加工厂,这个中介就是所谓的代理(不确定有没有委托模式这种说法)。
静态代理
首先定义购买接口
public interface Produce {
Tshirt produce(Order order);
}
实际的生产工厂:
public class Factory implements Produce {
@Override
public Tshirt produce(Order order) {
System.out.println("produce a t-shirt");
}
}
中间代理:
public class StaticProxy implements Produce {
private Factory factory;
public StaticProxy(Factory factory) {
this.factory = factory;
}
@Override
public Tshirt produce(Order order) {
factory.produce(order)
}
}
实际使用的时候
public static void main(String[] args) {
Order order = new Order();
StaticProxy proxy = new StaticProxy(new Factory());
Tshirt tshirt = proxy.produce(design);
}
这样的好处在于调用接口的人不直接依赖于业务执行的具体方式,将两者进行了解耦。如果工厂不接受生产件数小于100的订单时,只需要在Proxy里面定制相应的规则即可,而不需要去修改Factory类里的produce函数。
public class StaticProxy implements Produce {
// ...
private boolean checkAmount(Order order) {
if (order.amount < 100) {
return false;
}
return true;
}
@Override
public Tshirt produce(Order order) {
if (checkAmount(order)) {
return factory.produce(order);
}
// ...进行错误处理
return null;
}
}
缺点
如果想要为代理类的方法添加统一的执行前置操作或后置操作时,接口数量较多的情况下需要复制粘贴大量代码。比如想在生产T-shirt之前添加采购原材料,生产完之后发货这两个操作,在代理仅代理生产T-shirt时还好,如果它还代理了羽绒服、棉服、毛衣等一系列产品呢,一个一个复制粘贴显然是不优雅的。
动态代理
动态代理就解决了静态代理的问题,他可以为一个interface里的所有方法添加统一的前置操作和后置操作,在日志系统这样的地方就非常好用,因为很多功能模块都需要日志记录。本质上通过反射拿到需要执行的Method并在调用之前进行处理
Factory类和Produce接口和原来一致
public class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throw Throwable {
buyMaterials();
Object result = method.invoke(obj, args); // 调用的方法
deliverGoods();
}
}
使用的代码:
public static void main(String[] args) {
DynamicProxy proxy = new DynamicProxy(new Factory());
Produce produce = Proxy.newProxyInstance(Produce.class.getClassLoader(), new Class[] {Produce.class}, proxy);
produce.produce(new Order());
}
代理模式的要点
面向接口:客户类不要直接操作具体的业务类,这点其实适用于其他很多地方,是解耦的一个关键。
代理类和业务类实现同样的接口: 这点主要体现在使用静态代理的时候,逻辑看着更清晰些
无关吐槽
准备拿kotlin写的,结果老是报参数数量不对的错误,放弃了,好菜啊