手把手教你学设计模式-静态代理(简单易懂)
设计模式-静态代理
不要生搬硬套去使用设计模式,这样会适得其反,我们应该去学习这种思想。
大部分人对于设计模式的实际应用没有明确的意识,也许许多设计模式在你开发中已经使用过了,但你却不知道。
事实上,网上很多人举的例子都有些扯,这些人并没有实战经验,只不过在网上找一些八股文看了看。你在网上搜索 “设计模式
” 时,会出现很多文章,但是他们举的例子都是一些没有实战根据的,就有点类似于 “鸟会飞” 这样的例子,是个人都知道鸟会飞,举这样的例子很显然于实际开发没有半毛钱关系,但是给人的感觉是 “我懂了,这就是设计模式”
,这也就是导致很多人感觉自己学会了设计模式,但是工作中依然写着一堆又一堆的代码,完全不知道何时用什么设计模式可以使自己代码的可读性变高。
文章目录
- 设计模式-静态代理
- 前言
- 使用场景
- 不用设计模式
- 使用设计模式
- 总结
前言
这一章要讲的是设计模式中的 静态代理 模式,问题来了什么是代理模式呢?使用它有什么优势?
给大家举一个小小的例子来解释一下什么是设计模式,假设你女朋友叫闪送给你送了一本书,在这个过程中,闪送快递员就可以理解为是你女朋友的代理,你女朋友委托闪送快递员将书送到你手中。
从这个小小的例子中,你就已经对代理有了印象,就是 委托某人去做某件事
,还有很多例子,比如快递、运营商、外包公司等等,这些都是代理思想。
那我们为什么要用代理模式呢?
那上面例子来说,如果不用代理模式的话也是可以的,不过就会显得很沉重,你女朋友坐地铁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()方法,很显然,我们已经实现了该需求。
这时候可能有人要问,那上面的继承和现在的组合好像都可以实现,并且代码都差不多,为什么推荐使用组合呢?这个后面会出一章专门讲解 “设计原则”。
总结
静态代理模式其实就是 被代理类不方便或者不能够直接修改源代码时,代理类持有被代理类的实例,可以对被代理类进行聚合处理,从而达到增强被代理的目的。
手把手教你学设计模式-静态代理(简单易懂)相关推荐
- 手把手教你学Dapr - 5. 状态管理
介绍 使用状态管理,您的应用程序可以将数据作为键/值对存储在支持的状态存储中. 您的应用程序可以使用 Dapr 的状态管理 API 使用状态存储组件来保存和读取键/值对,如下图所示.例如,通过使用 H ...
- oracle数据库更新语句_20_手把手教你学Python之操作数据库
数据库是数据的仓库,将大量数据按照一定的方式组织并存储起来,方便进行管理和维护,例如快速检索和统计等.数据库的主要特点: 以一定的方式组织.存储数据: 能为多个用户共享: 与程序彼此独立. -- 数据 ...
- 手把手教你学Python之波士顿房价预测(scikit-learn的应用)
目录 1.波士顿房价预测介绍 2.线性回归算法 3.调用scikit-learn库实现房价预测 1.波士顿房价预测介绍 问题描述:波士顿房价数据集统计的是20世纪70年代中期波士顿郊区房价的中位数,统 ...
- 手把手教你学Python之Pandas(一文掌握数据分析与处理库-Pandas)
目录 基本结构之Series Series对象的创建 Index对象介绍 Series中数据的访问 Series中常用方法 基本结构之DataFrame DataFrame的创建 DataFrame ...
- 培训讲师的自我修养——《手把手教你学Java》
当前,人才是困扰IT企业发展的第一大问题,企业间竞争的本质就是人才的竞争.然而人才却有"结构性过剩"的问题,就是因为有高深的理论.尖端的技术.耀眼的学位的"人材" ...
- 手把手教你学51单片机——函数进阶与按键
目录 写在前面 一.单片机最小系统解析 1.1电源 1.2晶振 1.3复位电路 二.C语言--函数 2.1函数的调用 2.2函数的形参和实参 三.按键 3.1独立按键 3.2独立按键控制led数码管显 ...
- 手把手教你学Python之文件操作(一文掌握文件操作)
目录 1.Python中文本文件的读写 2.Python中常用的文件与文件夹操作方法 3.Python中Excel文件的读写 4.Python读取Excel文件案例 为了保存数据,方便修改和分享,数 ...
- 第11章 UART 串口通信(手把手教你学51单片机pdf部分)
手把手教你学51单片机-C语言版.pdf
- python global用法_14_手把手教你学Python之函数(下)
变量作用域:根据变量定义的位置,可将变量分为全局变量和局部变量. 全局变量:定义在函数外面的变量,可以在多个函数中进行访问,但不能执行赋值操作.如果有赋值语句,相当于创建了一个同名的局部变量: 局部变 ...
最新文章
- Extmail + Postfix on Debian5
- win2008server设置问题
- Flex TextInput只允许输入数字等字符及字符数限制
- DedeCMS生成首页html静态文件的教程
- Android Studio 构建
- Pytorch基础(九)——损失函数
- python之路——内置函数和匿名函数
- hibernate状态转换关系图【原】
- kindeditor 限制上传图片大小及宽高
- android定位获取坐标系,Android 定位坐标过滤算法实现
- pip换源,解决pip下载超时,连接失败等问题
- debug模式不报错,release模式报错
- 8583:全面掌握ISO8583报文协议zz
- php 汉字转拼音 扩展,PHP中文转拼音扩展
- android刷win8,驰为VX8 3G Win8刷安卓系统固件教程发布
- Python3.10.2安装教程
- 洲际酒店集团加速布局粤港澳大湾区,与华侨城酒店集团达成合作
- 关于任天堂,你不了解的9件事
- 在Allegro软件中的Groups组创建之后怎么进行打散呢?
- CISA国际注册信息系统审计师
热门文章
- Android ADB命令?这一次我再也不死记了!
- 每日新闻 | 旷视印奇发布公开信:人工智能必将造福所有人
- html5 aside图片,HTML5标签:aside元素的使用方法及作用
- 基于神经网络的目标检测论文之目标检测方法:改进的SSD目标检测算法
- 联通查身份证名下有几张卡
- 橙子02-Hadoop生态系统
- Servlet的destory方法没有打印到控制台
- Python小白学习笔记六 (面向对象 1 )
- android路由跳转,2021年你与字节跳动只差这份笔记,使用指南
- [c#美味] Guid ToString 格式知多少?