如何优雅地替换一个实现

前两天,我所在的项目有一个小的技术改动,打算把访问Redis的密码从数据库挪到配置文件里。以前的代码类似下面这样:640?wx_fmt=png用户第一次调用GetDatabase时,根据传入的数据库连接字符串访问数据库,从某个表里取出带密码的Redis连接字符串,然后建立Redis链接。至于替换成从配置文件中读取地址和密码,你可能10秒就想到了办法,然后不到10分钟就完成了下面的修改。640?wx_fmt=png完美,不是吗?不但达到了目的,还删除了一个无用的方法。但这是最佳的替换方式吗?我是说,要想把某个实现替换成另一个实现,就应该这么直接上吗?前两天我在公司的小电风扇坏了,电源线和风扇接触不良,只有在某一个特定位置才能通电。640?wx_fmt=png而我的一个同事的小风扇的电源是可插拔的,如果电源线坏了,换一根就是了。 640?wx_fmt=png我看到后惊呼:卧槽,接口隔离对于系统容易发生变化(易坏也属于变化)的部分,使用接口(电源线接头)对其进行隔离,如果变化了(线坏了),就用其他实现了同样接口的东西替换(即便没坏,想换个颜色也是很方便的)。这样的设计才叫设计啊。你也能看到,之前的实现和真正建立Redis连接的代码耦合在一起。本来嘛,先构建一个ConfigurationOptions,再基于这个options建立连接,很自然的事情。但现在要替换的,其实就是这个构建ConfigurationOptions的实现方式。以前是基于DB,现在基于配置。一个实现要被替换,说明什么呢?说明这是代码的一个变化方向。遇到变化的时候我们应该怎么处理呢?当然是创建一个接口来隔离这个变化。以前为什么没有隔离而是耦合在一起呢?是因为没有识别出这是一个变化方向。慢着,不要着急吐槽前人,犯这样的错误其实是很正常的事情,甚至都不能称其为一个错误。我们很难一开始就识别出业务或技术上的所有变化方向。但当变化真正出现的时候,也别急着着手修改。它以前不是一个变化方向,但现在是了。既然是了,就用接口隔离出来呗。好在代码是可以随时修改的,比电风扇强。我们重构最一开始的代码,把构建ConfigurationOptions的代码抽取出来。640?wx_fmt=png再把GetRedisConfigurationOptions方法抽取到新建的RedisConfigurationOptionsProvider类中。640?wx_fmt=png一开始的RedisCacheProvider类现在变成了下面这样。640?wx_fmt=png这时候已经具备了抽取接口的条件。640?wx_fmt=png接下来我们为IRedisConfigurationOptionsProvider接口添加一个新的实现,基于配置来读取Redis连接和密码。640?wx_fmt=png再回到RedisCacheProvider类中,将接口的实现替换为ConfigBasedConfigurationOptionsProvider640?wx_fmt=png再删除旧的RedisConfigurationOptionsProvider类,大功告成。由于引入了修改的复杂度(抽取类、接口,引入新的实现),以前10分钟能完成的工作,现在大概需要半个小时了。但这样做的好处也显而易见。我们识别出了一个新的代码变化方向,并用接口对其进行了隔离。以后再发生变化,只需要提供一个新的实现就好了,也遵循了开放-封闭原则。你可能不觉得这样做有什么好处,毕竟混在一起写也没有不会造成什么麻烦。的确这里的逻辑非常简单,即使耦合在一起也没什么大不了。但如果项目大了,很容易处处都是这样的耦合。当一个类里出现多处这样的耦合时,“发散式变化”的坏味道就出来了。如果你熟悉面向对象设计,可能已经脱口而出了,“这不就是抽象分支吗?”。没错,是的。抽象分支就是替换一个实现的最佳实践,小到一个类,大到一个基础设施,都是如此。点击阅读原文,可以看到Martin Fowler关于抽象分支的文章。你是如何替换一个实现的?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

莫队——三种题型

普通莫队 P3901 数列找不同 Thinking 一定是用可以用莫队来写题&#xff0c;这点是不用质疑的&#xff0c;所以那就简单了&#xff0c;只需要判断每次询问的区间是否满足r−l1numr - l 1 numr−l1num就行了。 Coding1Coding_1Coding1​ 莫队写法 #include <bits/stdc…

P5357 【模板】AC自动机(二次加强版) fail树

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 这个只能搞failfailfail树了&#xff0c;让后跑一遍即可。 重复的字符串记一个&#xff0c;让后其他的都跟他一个答案即可。 // Problem: P3796 【模板】AC自动机&#xff08;加强版&…

10分钟了解一致性hash算法

应用场景当我们的数据表超过500万条或更多时&#xff0c;我们就会考虑到采用分库分表&#xff1b;当我们的系统使用了一台缓存服务器还是不能满足的时候&#xff0c;我们会使用多台缓存服务器&#xff0c;那我们如何去访问背后的库表或缓存服务器呢&#xff0c;我们肯定不会使用…

Educational Codeforces Round 114 (Rated for Div. 2) D. The Strongest Build 暴力 + bfs

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 你有nnn个装备槽&#xff0c;每个槽里面有cic_ici​个力量加成&#xff0c;对于每个槽只能选一个力量加成&#xff0c;现在给你mmm个力量组合[b1,b2,...,bn][b_1,b_2,...,b_n][b1​,b2​,...,bn​]代表这个力…

[SCOI2008]着色方案(DP)

题目链接 思想 显然我们后面的决策是跟前一步相关的&#xff0c;因此我们可以考虑DP&#xff0c;可以用一个15维的数组来进行转移&#xff0c;但是这样显然回mle&#xff0c;所以我们考虑如何压缩状态&#xff0c;由于1<Ci<51 < C_i < 51<Ci​<5&#xff0…

创业周年记:召唤神龙一周年小记

2018年8月8日&#xff0c;我决定离开腾讯的光环&#xff0c;辞职开始创业。《回顾4180天在腾讯使用C#的历程&#xff0c;开启新的征途》记录了我所说的拥有七龙珠&#xff0c;去召唤神龙&#xff0c;今天正好历时一年时间&#xff0c;非常有必要来回顾过去一年的创业历程。迎接…

1285. 单词 ac自动机 + fail树

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 一篇论文由若干单词构成&#xff0c;且单词间是隔开的&#xff0c;给你nnn个单词&#xff0c;要求你计算每个单词在论文中出现了多少次。 1≤n≤2001\le n\le 2001≤n≤200&#xff0c;所有单词总长不超过1e…

Bitset瞎搞

Bitset字符匹配 Regular Number /*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc.h> #define mp make_pair #define pb push_back #define endl \nusing namespace std;typedef long long ll; typedef unsigned long lo…

「数据ETL」从数据民工到数据白领蜕变之旅(三)-除了Excel催化剂之外PowerQuery新物种同样值得期待...

在自助式BI时代以前&#xff0c;Excel级别的数据ETL工作&#xff0c;非常低效&#xff0c;动不动就要启用VBA来完成一些常见的需求&#xff0c;自带的原生功能&#xff0c;未能满足大量的繁琐数据ETL刚需功能。在Excel2010后&#xff0c;PowerQuery以插件的形式横空出现&#x…

Codeforces Round #743 (Div. 2) D. Xor of 3 模拟 + 构造

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个010101序列aaa&#xff0c;定义一次操作是选择一个[1,n−2][1,n-2][1,n−2]范围内的下表&#xff0c;将ai,ai1,ai2a_i,a_{i1},a_{i2}ai​,ai1​,ai2​都变成ai⊕ai1⊕ai2a_i\oplus a_{i1} \oplus a_…

Docker系列之烹饪披萨(二)

上一篇我们讲解了虚拟机和容器的区别&#xff0c;本节我们来讲讲Docker中关于Dockerfile、镜像、容器等基本概念。Docker是一个在容器内开发、部署、运行应用程序的平台&#xff0c;Docker本质上是容器化的代名词&#xff0c;容器对于提高软件开发和数据科学的安全性&#xff0…

线段树平方和板子

题目测试链接 代码 /*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc.h> #define mp make_pair #define pb push_back #define endl \n #define mid (l r >> 1) #define lson rt << 1, l, mid #define rson…

Codeforces Round #743 (Div. 2) E. Paint 区间dp + 暴力

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个有nnn个像素的图像&#xff0c;每个像素都有一个颜色aia_iai​&#xff0c;保证每种颜色的图像不会超过202020个。你现在每次可以选择一个颜色&#xff0c;并选择一段连续的像素&#xff0c;要求连续…

史上最能“拜客户教”的公司,是如何做到持续交付的?(第2趴)|DevOps案例研究...

内容来源&#xff1a;DevOps案例深度研究 –Amazon持续交付之道战队&#xff08;本文只展示部分PPT及研究成果&#xff0c;更多细节请关注案例分享会&#xff0c;及本公众号。&#xff09;本案例内容贡献者&#xff1a;单冰 (Topic Leader)、 赵栋、梁兴龙、李杰、毛艳清、牛恒…

C 简单瞎搞题(牛客练习赛22)(bitset优化dp)

Bitset优化Dp 题目链接 一般DP做法 显然后面的数是与前面的数字相关的&#xff0c;所以我们有dp数组&#xff0c;dp[i][j]dp[i][j]dp[i][j]选取了jjj个数&#xff0c;iii是否可以被创造出来&#xff0c;如果可以其值为1&#xff0c;否则为0。 所以我们显然有如下的状态转移…

AtCoder Regular Contest 125

传送门 A−DialUpA-Dial UpA−DialUp 贪心贪心贪心 首先当bbb有aaa没有的元素的时候显然无解&#xff0c;否则我们可以找到离a1a_1a1​最近的一个!a1!a_1!a1​&#xff0c;让后交替着来构造bbb即可。 int n,m; int a[N],b[N];int main() { // ios::sync_with_stdio(false); /…

ASP.NET Core on K8S深入学习(3)Deployment

上一篇《部署过程解析与安装Dashboard》中我们了解K8S的部署过程&#xff0c;这一篇我们来了解一下K8S为我们提供的几种应用运行方式&#xff1a;Deployment、DaemonSet与Job&#xff0c;它们是Kubernetes最重要的核心功能提供者。考虑到篇幅和更新速度&#xff0c;我将其分为两…

Codeforces Round #742 (Div. 2) F. One-Four Overload 构造 + 二分图染色

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个n∗mn*mn∗m的矩形&#xff0c;包含...和XXX&#xff0c;你有两种颜色&#xff0c;你需要给...染色使得每个XXX上下左右相邻的...其两种颜色个数相同&#xff0c;输出一种合法方案。 1≤n,m≤5001\l…

同余最短路(P3403 跳楼机)

同余最短路 前置 给定m个数&#xff0c;这m个数可以重复取&#xff0c;问最大的这m个数不能拼成的数&#xff0c;或者给定一定范围&#xff0c;范围里有多少个数是这m个数可以拼成的&#xff0c;对于这种问题我们可以考虑同余最短路的算法。 P3403 跳楼机 同余最短路介绍 …

8月语言排行:C#继续呈现增长态势

TIOBE 编程语言排行榜 8 月更新已公布&#xff0c;排名前十的分别是&#xff1a;Java, C, Python, C, C#, Visual Basic .NET, JavaScript, PHP, Objective-C 和 SQL。和上个月唯一的不同之处在于 Objective-C 和 SQL 的排名发生了交换。事实上&#xff0c;上周 Dice Insights …