代理模式
静态代理
什么是静态代理?
当前类A不能直接访问目标类C时,需要通过手工实现一个中介类B来访问C。这就是静态代理
代理模式的作用?
控制访问、功能增强
示例(静态代理)
Factory 厂家
Merchant 商家
UserXiaoMing 用户
Sell 公共行为接口(卖东西)
/*
* 小黄GPU厂家 不对用户直销 只给商家 问就是合作关系量大
* */
public class Factory implements Sell {
@Override
public int sellGpu() {
return 500;
}
}
/*
* 华珂商家(静态代理,手动实现的代理)
* */
public class Merchant implements Sell {
private Factory factory = new Factory();
// 做代理(做中介,赚大钱)
@Override
public int sellGpu() {
return factory.sellGpu() + 888;
}
}
public interface Sell {
int sellGpu();
}
public class UserXiaoMing {
public static void main(String[] args) {
System.out.println("xiaoming 买 GPU 需要付出的钱是 : " + new Merchant().sellGpu());
}
}
// 控制台输出:
xiaoming 买 GPU 需要付出的钱是 : 1388
静态代理优缺点
-
静态代理缺点:
-
1、当 Sell 接口增加另外的 sellCpu() sellMemory() 时, 厂家、商家 都要变动,不解耦
-
2、当 Factory 厂家不断增加时, 相应的 商家也会不断增加,类膨胀
-
静态代理好处:
-
容易实现,容易理解, user 不能直接访问 厂家,需要中介类Merchant去访问
动态代理
什么是动态代理?
java运行时,调用jdk接口通过底层反射机制自动给你生成 Merchant 商家1、Merchant 商家2 、Merchant 商家3 …
这就叫做动态代理,发现与静态代理的不同点了吗? 不需要手动自己去写商家类了
如何使用动态代理?
1、Java反射包类与接口
好麻烦,必须得构建初 handler 对象先,
再去调用 Proxy.newProxyInstance(loader,interfaces,handler);
示例
厂商+公共接口
/*
* 电脑厂商 不直接对用户销售
* */
public class ComputerFactory implements Sell {
@Override
public float sellCpu() {
return 888.999f;
}
@Override
public float sellMemory(int buyNumbs) {
return buyNumbs * 499.99f;
}
@Override
public float sellPig() {
return 0;
}
}
/*
* 肉类厂商 不直接对用户销售
* */
public class MeatsFactory implements Sell {
@Override
public float sellCpu() {
return 0f;
}
@Override
public float sellMemory(int buyNumbs) {
return 0;
}
@Override
public float sellPig() {
return 15.55f;
}
}
/*
* 厂家公共行为出口
* */
public interface Sell {
float sellCpu();
float sellMemory(int buyNumbs);
float sellPig();
}
动态代理类
InvocationHandler.invoke 核心
public class Handler implements InvocationHandler {
// target: 代理对象
private Object target;
// input: 输入厂家对象
public Object getProxy(Object input) {
this.target = input;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取到公共接口对应方法
Object res = method.invoke(target, args);
// 对公共接口方法进行 增强逻辑/业务逻辑/中介加钱逻辑
if (method.toString().contains("sellCpu")) {
res = (float) res + 2000.00f;
} else if (method.toString().contains("sellMemory")) {
res = (float) res - 10000.00f;
}
return res;
}
}
测试类
public class XiaoNiuUser {
public static void main(String[] args) {
Handler handler = new Handler();
Sell computerProxy = (Sell) handler.getProxy(new ComputerFactory());
System.out.println("真坑啊!厂家卖 888.999,到你这就卖 sellCpu : " + computerProxy.sellCpu());
System.out.println("真坑啊!厂家卖 499.99/根,到你这就卖 sellMemory :" + computerProxy.sellMemory(10));
Sell meatsProxy = (Sell) handler.getProxy(new MeatsFactory());
System.out.println("真坑啊!厂家卖 15.55,到你这就卖 sellPig :" + meatsProxy.sellPig());
}
}
控制台:
真坑啊!厂家卖 888.999,到你这就卖 sellCpu : 2888.999
真坑啊!厂家卖 499.99/根,到你这就卖 sellMemory :-5000.1
真坑啊!厂家卖 15.55,到你这就卖 sellPig :15.55
动态代理好处: 看上面代码,没有去修改任何厂商的代码,就能直接加钱卖。 相当于在 厂商 – [黑商] --用户 中间包装了一层 “黑商” ,符合开闭原则。
2、CGLIB动态代理
别人封装好工具类了 直接用
示例
动态代理优缺点
缺点:
优点:
1)代理类数量可以很少
2)当你修改了接口中的方法时,不会影响代理类