设计模式-静态代理

不要生搬硬套去使用设计模式,这样会适得其反,我们应该去学习这种思想。
大部分人对于设计模式的实际应用没有明确的意识,也许许多设计模式在你开发中已经使用过了,但你却不知道。
事实上,网上很多人举的例子都有些扯,这些人并没有实战经验,只不过在网上找一些八股文看了看。你在网上搜索 “设计模式” 时,会出现很多文章,但是他们举的例子都是一些没有实战根据的,就有点类似于 “鸟会飞” 这样的例子,是个人都知道鸟会飞,举这样的例子很显然于实际开发没有半毛钱关系,但是给人的感觉是 “我懂了,这就是设计模式”,这也就是导致很多人感觉自己学会了设计模式,但是工作中依然写着一堆又一堆的代码,完全不知道何时用什么设计模式可以使自己代码的可读性变高。


文章目录

  • 设计模式-静态代理
  • 前言
  • 使用场景
  • 不用设计模式
  • 使用设计模式
  • 总结

前言

这一章要讲的是设计模式中的 静态代理 模式,问题来了什么是代理模式呢?使用它有什么优势?
给大家举一个小小的例子来解释一下什么是设计模式,假设你女朋友叫闪送给你送了一本书,在这个过程中,闪送快递员就可以理解为是你女朋友的代理,你女朋友委托闪送快递员将书送到你手中。
从这个小小的例子中,你就已经对代理有了印象,就是 委托某人去做某件事,还有很多例子,比如快递、运营商、外包公司等等,这些都是代理思想。
那我们为什么要用代理模式呢?
那上面例子来说,如果不用代理模式的话也是可以的,不过就会显得很沉重,你女朋友坐地铁2小时给你送书,你网上购买了东西需要亲自到商家去拿货等等,映射到程序中也是类似的。


使用场景

对于静态代理来说,在实际开发中更多并不像 前言 里所讲的,从一开始就设计好的。工作中,更多的是 使用静态代理去“弥补”开发时的设计不足,这才是静态代理使用最多的地方(至少对于我来说是的)。当然,在你使用熟练之后就可以在开发前预测到未来可能会遇到的问题,提前使用设计模式去合理设计类于类之间的关系。

假设公司提供了一个id生成器的jar包,供整个公司使用,如下:

public interface IDCreator {/*** 生成一个唯一id* @return*/String create();
}public class StandardIDCreator implements IDCreator {@Overridepublic String create() {return UUID.randomUUID().toString();}
}

该jar包中提供了一个接口和一个默认实现,而我们在项目中使用时,直接去调用StandardIDCreator.create()即可获得一个唯一的id,并且我们在项目中一直也是这样使用的。这时,产品蹦出来说,如果用户通过邀请注册的账号,那我们的id规则需要变更一下,在id之前加上 "app_"这样一个前缀,通过其他渠道注册的用户依然使用原来的id规则。
我们之前的注册服务代码如下:

public class APP1Service {IDCreator idCreator;public APP1Service(){idCreator = new StandardIDCreator();}public void register(){String userId = idCreator.create();}
}

可以看到,我们 直接使用 idCreator.create(); 去生成的id。

不用设计模式

如果在不使用设计模式的情况下,我们可以采取这样几种方法去完成这个需求,在邀请注册的服务中,直接使用 “app_”.concat(idCreator.create()),直接采取这种方式去完成,很显然这样也是可以的,但是这样会改动源代码,违反了开闭原则,而且,如果后续产品要求将 “app_” 前缀 改为 “spc_”前缀的话,你就又需要去改动业务逻辑了,这样做无疑是增加了危险性,因为每次改动业务代码都有可能导致bug的出现。
那么我们先来看一下不使用设计模式的情况下,代码是什么样子的。

public void register(){//do somethingString userId = idCreator.create();String newUserId = "app_".concat(userId);//do something}

可以看到,我们直接在业务代码中去修改了代码,这只是个简单的例子,可能大家无法感受到,如果这个业务中包含了很多的复杂逻辑以及计算逻辑,那么更改之后需要对改方法进行回归测试。
还有一种方式就是,由于IDCreator是jar包中提供的,我们无法对其源代码进行更改,这时我们会想到,新建一个类去实现 IDCreator ,在里面去实现 create()方法,这种想法是好的,当然你也可以这样做,但是会显的很鸡肋,需要完全重写 create()方法,就像下面这样。

public class CustomIDCreator implements IDCreator{@Overridepublic String create() {String id = UUID.randomUUID().toString();return "app_".concat(id);}
}

我们重写定义了一个 CustomIDCreator 类去实现了 IDCreator接口,将create()方法进行重写,可以看到 CustomIDCreator 和 StandardIDCreator 中存在大量相同代码,完全可以进行复用,我们可以用 CustomIDCreator 去继承 StandardIDCreator ,重写其中的 create()方法,如下:

public class CustomIDCreator extends StandardIDCreator{@Overridepublic String create() {String id = super.create();return "app_".concat(id);}
}

这里,我们通过继承实现了代码的复用,也可以说是对 StandardIDCreator 进行了增强。到这里,其实已经很好的解决了这个需求。
那这样看来,我们上面的例子中继承在某种意义上好像是对父类的增强,这种就属于强耦合,并且存在继承关系,如果后续又修改其他需求,这时候你就又需要创建一个类再去继承 CustomIDCreator 或者 StandardIDCreator,由于java是单继承的,所以再没有考虑清楚之前,尽量不要使用继承,尽量要使用组合,除非你能保证他们之间有着直接联系,后续大概率不会又变更时可以选择继承。

使用设计模式

public class IDCreatorProxy implements IDCreator{private IDCreator idCreator;public IDCreatorProxy(IDCreator idCreator){this.idCreator = idCreator;}@Overridepublic String create() {String id = idCreator.create();return "app_".concat(id);}
}

在这里我们新建了一个代理类并实现了IDCreator,获得了重写 create() 的机会,并且在内部持有一个 类型为 IDCreator 的成员变量,我们重写了create()方法,很显然,我们已经实现了该需求。
这时候可能有人要问,那上面的继承和现在的组合好像都可以实现,并且代码都差不多,为什么推荐使用组合呢?这个后面会出一章专门讲解 “设计原则”。


总结

静态代理模式其实就是 被代理类不方便或者不能够直接修改源代码时,代理类持有被代理类的实例,可以对被代理类进行聚合处理,从而达到增强被代理的目的。

手把手教你学设计模式-静态代理(简单易懂)相关推荐

  1. 手把手教你学Dapr - 5. 状态管理

    介绍 使用状态管理,您的应用程序可以将数据作为键/值对存储在支持的状态存储中. 您的应用程序可以使用 Dapr 的状态管理 API 使用状态存储组件来保存和读取键/值对,如下图所示.例如,通过使用 H ...

  2. oracle数据库更新语句_20_手把手教你学Python之操作数据库

    数据库是数据的仓库,将大量数据按照一定的方式组织并存储起来,方便进行管理和维护,例如快速检索和统计等.数据库的主要特点: 以一定的方式组织.存储数据: 能为多个用户共享: 与程序彼此独立. -- 数据 ...

  3. 手把手教你学Python之波士顿房价预测(scikit-learn的应用)

    目录 1.波士顿房价预测介绍 2.线性回归算法 3.调用scikit-learn库实现房价预测 1.波士顿房价预测介绍 问题描述:波士顿房价数据集统计的是20世纪70年代中期波士顿郊区房价的中位数,统 ...

  4. 手把手教你学Python之Pandas(一文掌握数据分析与处理库-Pandas)

    目录 基本结构之Series Series对象的创建 Index对象介绍 Series中数据的访问 Series中常用方法 基本结构之DataFrame DataFrame的创建 ​DataFrame ...

  5. 培训讲师的自我修养——《手把手教你学Java》

    当前,人才是困扰IT企业发展的第一大问题,企业间竞争的本质就是人才的竞争.然而人才却有"结构性过剩"的问题,就是因为有高深的理论.尖端的技术.耀眼的学位的"人材" ...

  6. 手把手教你学51单片机——函数进阶与按键

    目录 写在前面 一.单片机最小系统解析 1.1电源 1.2晶振 1.3复位电路 二.C语言--函数 2.1函数的调用 2.2函数的形参和实参 三.按键 3.1独立按键 3.2独立按键控制led数码管显 ...

  7. 手把手教你学Python之文件操作(一文掌握文件操作)

    目录 1.Python中文本文件的读写 2.Python中常用的文件与文件夹操作方法 3.Python中Excel文件的读写 4.Python读取Excel文件案例​ 为了保存数据,方便修改和分享,数 ...

  8. 第11章 UART 串口通信(手把手教你学51单片机pdf部分)

    手把手教你学51单片机-C语言版.pdf  

  9. python global用法_14_手把手教你学Python之函数(下)

    变量作用域:根据变量定义的位置,可将变量分为全局变量和局部变量. 全局变量:定义在函数外面的变量,可以在多个函数中进行访问,但不能执行赋值操作.如果有赋值语句,相当于创建了一个同名的局部变量: 局部变 ...

最新文章

  1. Extmail + Postfix on Debian5
  2. win2008server设置问题
  3. Flex TextInput只允许输入数字等字符及字符数限制
  4. DedeCMS生成首页html静态文件的教程
  5. Android Studio 构建
  6. Pytorch基础(九)——损失函数
  7. python之路——内置函数和匿名函数
  8. hibernate状态转换关系图【原】
  9. kindeditor 限制上传图片大小及宽高
  10. android定位获取坐标系,Android 定位坐标过滤算法实现
  11. pip换源,解决pip下载超时,连接失败等问题
  12. debug模式不报错,release模式报错
  13. 8583:全面掌握ISO8583报文协议zz
  14. php 汉字转拼音 扩展,PHP中文转拼音扩展
  15. android刷win8,驰为VX8 3G Win8刷安卓系统固件教程发布
  16. Python3.10.2安装教程
  17. 洲际酒店集团加速布局粤港澳大湾区,与华侨城酒店集团达成合作
  18. 关于任天堂,你不了解的9件事
  19. 在Allegro软件中的Groups组创建之后怎么进行打散呢?
  20. CISA国际注册信息系统审计师

热门文章

  1. Android ADB命令?这一次我再也不死记了!
  2. 每日新闻 | 旷视印奇发布公开信:人工智能必将造福所有人
  3. html5 aside图片,HTML5标签:aside元素的使用方法及作用
  4. 基于神经网络的目标检测论文之目标检测方法:改进的SSD目标检测算法
  5. 联通查身份证名下有几张卡
  6. 橙子02-Hadoop生态系统
  7. Servlet的destory方法没有打印到控制台
  8. Python小白学习笔记六 (面向对象 1 )
  9. android路由跳转,2021年你与字节跳动只差这份笔记,使用指南
  10. [c#美味] Guid ToString 格式知多少?