一、代理模式
代理模式(Proxy)为其他的对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。
1. 代理模式的作用
- 在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。
2. 静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。
-
一个例子
- 创建服务接口 GameFactory
package cn.lazyfennec.proxydemo.service; public interface GameFactory { String make(); }
- 创建Ps4GameFactory和GameBoyFactory实现GameFactory
package cn.lazyfennec.proxydemo.real; import cn.lazyfennec.proxydemo.service.GameFactory; /** * @Author: Neco * @Description: * @Date: create in 2022/4/17 23:57 */ public class Ps4Factory implements GameFactory { @Override public String make() { return "ps4"; } }
package cn.lazyfennec.proxydemo.real; import cn.lazyfennec.proxydemo.service.GameFactory; /** * @Author: Neco * @Description: * @Date: create in 2022/4/18 0:08 */ public class GameBoyFactory implements GameFactory { @Override public String make() { return "game boy"; } }
- 创建代理类NecoProxy
4、创建执行类package cn.lazyfennec.proxydemo.proxy; import cn.lazyfennec.proxydemo.service.GameFactory; /** * @Author: Neco * @Description: * @Date: create in 2022/4/18 0:04 */ public class NecoProxy implements GameFactory { GameFactory factory; public NecoProxy(GameFactory factory) { this.factory = factory; } @Override public String make() { doSomethingBefore(); String make = factory.make(); System.out.println(make); doSomethingAfter(); return null; } // 售前服务 private void doSomethingBefore() { } // 售后服务 private void doSomethingAfter() { } }
package cn.lazyfennec.proxydemo.caller; import cn.lazyfennec.proxydemo.proxy.NecoProxy; import cn.lazyfennec.proxydemo.real.GameBoyFactory; import cn.lazyfennec.proxydemo.real.Ps4Factory; /** * @Author: Neco * @Description: * @Date: create in 2022/4/17 23:58 */ public class Tuhao { public static void main(String[] args) { // 土豪要去购买,代理 Ps4Factory ps4Factory = new Ps4Factory(); NecoProxy necoProxy = new NecoProxy(ps4Factory); necoProxy.make(); GameBoyFactory gameBoyFactory = new GameBoyFactory(); necoProxy = new NecoProxy(gameBoyFactory); necoProxy.make(); } }
- 静态代理总结
- 优点:不修改目标对象的功能前提下,对目标功能进行扩展。
- 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类被创建,类太多。同时一旦接口增加方法,目标与代理对象都要维护,增加维护成本。
3. 动态代理
-
代理类在程序运行时创建的代理方式被称为动态代理。
-
这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。
-
要点
- proxy 代理对象 - 由它分配代理对象
- InvocationHandler 标准化的代购流程
-
一个例子
- 创建服务接口 GameFactory,与静态代理一致
- 创建Ps4GameFactory和GameBoyFactory实现GameFactory,与静态代理一致
- 创建代理类NecoDynamicProxy
package cn.lazyfennec.proxydemo.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @Author: Neco * @Description: * @Date: create in 2022/4/18 0:34 */ public class NecoDynamicProxy implements InvocationHandler { public Object target; // 被代理的对象 public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Object getProxy() { // 我只负责与总公司联系,不再去接触具体的店铺 return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doSomethingBefore(); Object invoke = method.invoke(target, args); System.out.println(invoke); doSomethingAfter(); return null; } // 售前服务 private void doSomethingBefore() { System.out.println("pay"); } // 售后服务 private void doSomethingAfter() { System.out.println("is ok"); } }
- 创建执行类
package cn.lazyfennec.proxydemo.caller; import cn.lazyfennec.proxydemo.proxy.NecoDynamicProxy; import cn.lazyfennec.proxydemo.real.Ps4Factory; import cn.lazyfennec.proxydemo.service.GameFactory; /** * @Author: Neco * @Description: * @Date: create in 2022/4/18 0:43 */ public class TuhaoDynamic { public static void main(String[] args) { NecoDynamicProxy proxy = new NecoDynamicProxy(); Ps4Factory ps4Factory = new Ps4Factory(); proxy.setTarget(ps4Factory); GameFactory factory = (GameFactory) proxy.getProxy(); factory.make(); } }
4. 动态代理VS静态代理:
- 静态代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。
- 静态代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
5. 更高级的封装
- 加入 Spring Aop 和 Ioc
网友评论