署理模式:实现高效、可扩展的代码架构的必备利器

鼠扑  论坛元老 | 2024-11-10 09:02:39 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1068|帖子 1068|积分 3204

1. 署理模式

署理模式英文全称为 Proxy Pattern,也被称为委托模式,属于布局型计划模式的一种。
2. 定义

为其他对象提供一种署理以控制对这个对象的访问
3. 使用场景

当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个署理对象来间接访问
为了保证客户端使用的透明性,委托对象与署理对象须要实现雷同的接口
4. UML 类图


这个是我用 PlantUML 画的,关于 PlantUML,可以看我之前文章的介绍: [画流程图你还在用鼠标拖吗]
这里我们的 Client 是客户端,委托对象 RealSubject 和署理对象 ProxySubject 都实现了雷同的接口(这里是抽象类) Subject。
对应的代码仓库见:[Proxy Pattern Repo]
5. 署理模式分类

署理模式分为静态署理和动态署理
5.1 静态署理

署理类的 class 编译文件在代码运行前就已存在
5.2 动态署理

通过反射机制动态地生成署理者的对象,署理谁在执行阶段决定
6. 实战演练

我们通过一个实际的例子来演示静态署理和动态署理是如何通过代码来实现的
6.1 场景说明

   小李以前在公司上班时,遇到老板拖欠工资的事情,小李想通过法律途径来解决该问题。
由于小李没有专业的法律干系知识,因此须要一个律师来作为自己的诉讼署理人。
  6.2 静态署理实现

6.2.1 公共接口

我们首先须要定义一个署理类和委托类共同实现的接口,对应我们上文的 Subject,在这里我们定义接口为 ILawsuit。
  1. public interface ILawsuit {  
  2.     // 提交申请  
  3.     void submit();  
  4.     // 进行举证  
  5.     void burden();  
  6.     // 开始辩护  
  7.     void defend();  
  8.     // 诉讼完成  
  9.     void finish();  
  10. }
复制代码
6.2.2 委托类

接着我们定义委托类实现接口里面的具体功能,对应我们上文的 RealSubject,在这里我们定义接口为 Lee。
  1. public class Lee implements ILawsuit {  
  2.     @Override  
  3.     public void submit() {  
  4.         System.out.println("老板拖欠工资!特此申请仲裁!");  
  5.     }  
  6.     @Override  
  7.     public void burden() {  
  8.         System.out.println("这是合同书和过去一年的银行工资流水!");  
  9.     }  
  10.     @Override  
  11.     public void defend() {  
  12.         System.out.println("证据确凿!不需要再说什么了!");  
  13.     }  
  14.     @Override  
  15.     public void finish() {  
  16.         System.out.println("诉讼成功!判决老板即日起七天内结算工资");  
  17.     }  
  18. }
复制代码
6.2.3 署理类

接着我们定义署理类实现接口里面的具体功能,但是这里我们是通过调用委托类来达到实现接口具体功能的结果,对应我们上文的 ProxySubject,在这里我们定义接口为 Lawyer。
  1. public class Lawyer implements ILawsuit {  
  2.     // 代理类持有委托类的引用,以便调用委托类来实现接口的具体功能  
  3.     private ILawsuit mLawsuit;  
  4.     public Lawyer(ILawsuit lawsuit) {  
  5.         this.mLawsuit = lawsuit;  
  6.     }  
  7.     @Override  
  8.     public void submit() {  
  9.         mLawsuit.submit();  
  10.     }  
  11.     @Override  
  12.     public void burden() {  
  13.         mLawsuit.burden();  
  14.     }  
  15.     @Override  
  16.     public void defend() {  
  17.         mLawsuit.defend();  
  18.     }  
  19.     @Override  
  20.     public void finish() {  
  21.         mLawsuit.finish();  
  22.     }  
  23. }
复制代码
6.2.4 客户端

接着我们定义客户端来演示下结果,对应我们上文的 Client,在这里我们定义为 StaticProxyClient。
  1. public class StaticProxyClient {  
  2.     public static void main(String[] args) {  
  3.         ILawsuit lee = new Lee();  
  4.         ILawsuit laywer = new Lawyer(lee);  
  5.         laywer.submit();  
  6.         laywer.burden();  
  7.         laywer.defend();  
  8.         laywer.finish();  
  9.     }  
  10. }
复制代码
结果输出为:
  1. 老板拖欠工资!特此申请仲裁!
  2. 这是合同书和过去一年的银行工资流水!
  3. 证据确凿!不需要再说什么了!
  4. 诉讼成功!判决老板即日起七天内结算工资
复制代码
对应的代码仓库见:[Static Proxy Repo]
6.3 动态署理实现

上一节我们通过小李的例子讲述了静态署理的实现方式,如果我们用动态署理来实现的话,怎么实现,哪里须要修改呢?
   首先公共接口不须要修改,其次委托类也不须要修改。
须要修改的是署理类客户端
  6.3.1 公共接口

同 6.2.1,此处不再赘述
6.3.2 委托类

同 6.2.2,此处不再赘述
6.3.3 动态署理

我们定义动态署理,通过反射来调用委托类对应的接口方法。在这里我们定义接口为 DynamicProxy。
  1. public class DynamicProxy implements InvocationHandler {  
  2.     // 代理类持有委托类的引用,以便调用委托类来实现接口的具体功能  
  3.     private Object obj;  
  4.     public DynamicProxy(Object obj) {  
  5.         this.obj = obj;  
  6.     }  
  7.     @Override  
  8.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  9.         // 调用委托类的方法  
  10.         Object result = method.invoke(obj, args);  
  11.         return result;  
  12.     }  
  13. }
复制代码
可以看到,我们这里的代码和静态署理 6.2.3 的实现 Lawyer 相比简便了不少。
当然,大家应该留意到了,我们这里是动态署理而不是署理类,原因在于动态署理的署理类是动态构建的,以是它的体如今我们下文的 6.3.4 中。
6.3.4 客户端(署理类在此构建)

我们定义客户端来演示下结果,对应我们上文的 Client,在这里我们定义为 DynamicProxyClient。 署理类为我们动态构建的对象 lawyer 所对应的类,对应我们上文的 ProxySubject。
  1. public class DynamicProxyClient {  
  2.     public static void main(String[] args) {  
  3.         // 构建委托类  
  4.         ILawsuit lee = new Lee();  
  5.         // 将委托类传入动态代理  
  6.         DynamicProxy dynamicProxy = new DynamicProxy(lee);  
  7.         // 获取委托类的 ClassLoader  
  8.         ClassLoader loader = lee.getClass().getClassLoader();  
  9.         // 动态构建代理类  
  10.         ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader,  
  11.         new Class[]{ILawsuit.class}, dynamicProxy);  
  12.         lawyer.submit();  
  13.         lawyer.burden();  
  14.         lawyer.defend();  
  15.         lawyer.finish();  
  16.     }  
  17. }
复制代码
结果输出为:
  1. 老板拖欠工资!特此申请仲裁!
  2. 这是合同书和过去一年的银行工资流水!
  3. 证据确凿!不需要再说什么了!
  4. 诉讼成功!判决老板即日起七天内结算工资
复制代码
对应的代码仓库见:[Dynamic Proxy Repo]
6.4 静态署理和动态署理的适用场景

静态署理通常适用于以了局景:

  • 署理对象较少:当系统中署理对象数量较少,且署理逻辑相对固定时,可以使用静态署理。
    因为静态署理须要手动编写署理类,以是署理对象较多时会导致代码量增加。
  • 编译时确定署理逻辑:如果署理逻辑在编译时就能确定,且不须要在运行时改变,那么静态署理是一个很好的选择。它简单明白,易于理解。
动态署理则更适用于以了局景:

  • 署理对象较多:当系统中存在大量署理对象,且署理逻辑较为相似时,动态署理能够减少代码量,提高开辟效率。
  • 运行时改变署理逻辑:动态署理可以在运行时动态地改变署理逻辑,这使得它在处置惩罚复杂业务逻辑和变化的需求时更具优势。比方,在AOP(面向切面编程)中,可以通过动态署理实现横切关注点(如日志记录、事件管理等)的织入。

如果你看到了这里,以为文章写得不错就给个赞呗?
更多Android进阶指南 可以扫码 解锁更多Android进阶资料


敲代码不易,关注一下吧。ღ( ´・ᴗ・` )

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

鼠扑

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表