如何将复杂问题拆分成小问题?

关注点分离原则是一个帮助我们将复杂问题拆分成小问题的好方法。

什么是关注点?简单来说,在计算机科学中,关注点是能对程序代码产生影响的一组特定信息。比如,在面向对象编程中将关注点描述为对象,在面向函数编程中将关注点描述为函数,在架构设计中将模块、组件、框架描述为关注点,等等。

其实,在前面的文章里,我们也或多或少涉及了关注点分离原则的具体实践。比如,在分层架构中按照服务类型来划分层,层就被作为一个关注点。再比如,在类或方法的编码实现中按职责分离,就是将职责作为一个关注点。

那么,为什么应该使用关注点分离原则来拆分复杂问题?关注点分离原则到底说了些什么?它带给我们哪些启示?如何正确使用好这个原则?下面,我们就一起来看看

一、为什么用关注点分离原则拆分复杂问题

从编码实现的角度看,使用关注点分离来拆分复杂问题有两大好处。

第一,你破坏其他用户正在使用的现有功能的可能性会变小。 实际上,你可能遇见的绝大多数软件开发项目都过于复杂难懂,不仅修改一次影响多处,而且维护时也不知道哪些地方该改、哪些地方不该改,更别提什么高扩展性的代码了。不仅理解起来费劲,而且无论是在架构设计还是编码实现上,扩展性都很差。而当你分离了不同的关注点后,就可以避免不必要关注点的功能修改,因为与必须修改的代码相比,由不修改的代码而导致系统中断的可能性更小,也就是我们常说的不修改就不会引入 Bug。

第二,关注点分离能帮助你适应人类的短期记忆限制。 这在一些计算机早期研究的论文中便有提及过。就像我们看一篇文章一样,我们的短期记忆总是只能记住最近阅读过的简单问题,而对于一些复杂问题很快就会忘记。尽管现在信息的存储和查询效率远远高于过去,但是你在编程中依然无法理解那种过于庞大而复杂的问题,只有将不同关注点拆分出来,才能更好地去解决各个问题。

所以说,使用关注点分离来拆分复杂问题很有实践的价值。

二、两个视角下的关注点分离

关注点分离(Separation of Concerns,简称 SoC)是将计算机程序分隔为不同部分的设计原则。最早出现在 1974 年,那时它只是针对如何深入研究一门课程而提出的一种思考方法。

关注点分离原则的原理很简单,就是:先将复杂问题做合理的分解,再分别仔细研究程序上特定问题的侧面(关注点),最后解决得出的接口,再合成整体的解决思路

除了狭义上程序特定的关注点外,在广义上同样可以找到很多关注点,比如,我们很容易找到的关注点就是影响我们常用的软件设计的两个思考视角,也就是架构设计视角和编码实现视角。

1、架构设计视角

架构设计视角下的关注点分离侧重于整个系统内组件之间的边界划分,比如,层与层、模块与模块、服务与服务等。

通常我们都知道,局部的分离不代表整体的分离,因为模块与模块之间依然需要通信,一旦没有某种策略来限制相互通信的耦合度,架构稍不注意就会演变为大泥球式的架构。比如,我们常用 MVC 分层策略来做架构上的关注点分离。二者对比如下图所示:

在图中右侧的 MVC 架构中,我们将相关的主题聚合在某一层,这样便不再难以理解了。也就是,将层作为关注点来进行分离,通过解决每一个层的问题来实现整体问题的解决

同样,现在流行的微服务架构也是采用水平分离的策略来达到服务与服务之间关注点分离的目的,如下图所示:

虽说每个微服务的关注点可能完全不同,但通过统一的 API 层来进行通信就不会影响它们之间的相互配合。

总之,通过上面的两个例子可以看到:架构设计视角下的关注点分离更重视组件之间的分离,并通过一定的通信策略来保证架构内各个组件间的相互引用

2、编码实现视角

编码实现视角下的关注点分离主要侧重于某个具体类或方法间的边界划分,估计这里你立马会想到职责分离,没错,职责分离就是一种编码实现视角下关注点分离的优秀实践。比如,下面的代码实现(找出 3 个年龄大于 35 岁的员工的名字),就是基于操作职责相似性来进行关注点分离的,使用的是 Lambda 表达式。

如图中所示,我们的关注点现在变成了数据流上的操作步骤(过滤、映射、限制等),我们读取每一个用户信息数据后,都会经过相同的步骤来处理,这样不仅利于理解每一个步骤操作的具体含义,也更符合我们的思考习惯。

三、如何实现关注点分离

了解完架构设计和编码实现这两个视角后,接下来我们就开始学习如何正确实现关注点分离的方法。

无论是架构设计,还是程序设计,好的系统总是在不断地寻找可以分离的关注点。比如,网络 OSI 七层模型就是一个关注点分离的经典应用,那它是怎么做的呢?OSI 七层模型将网络传输分为七层,每一个层只关注于自己需要完成的事情,层与层之间通过自下而上的数据通信方式进行交互。

好的架构必须使每个关注点相互分离,也就是说系统中的一部分发生了改变,并不会影响到其他部分。这主要体现在这三个方面:①即使需要改变,也能够清晰地识别出哪些部分需要改变;②如果需要扩展架构,尽量做到影响最小化;③已经可以工作的部分还都将继续工作。

除了快速识别出不变和变化的部分外,在实际实施过程中,还需要一些具体的的技巧来帮助你实现关注点分离。那就是:

  • 在架构设计上,做到策略和机制分离;

  • 在编码实现上,做到使用和创建分离。

1、技巧一:在架构设计上,做到策略和机制分离

在架构设计时,我们面对的是不同的系统、服务、类库、框架、组件等元素,要想做到关注点分离,除了将关注点从代码上移到更高的抽象层次以外,还需要做到策略和机制分离。

  • 机制是指各种软件要素之间的结构关系和运行方式。可以理解为实现某个功能所需要的基础操作和通用结构。在代码中相对稳定,表现形式有:通用算法、流程、数据结构等可以起到不可变作用的部分。

  • 策略是指可以实现软件发布目标的编码方案集合。在代码中相对不稳定,表现形式有:业务逻辑、接口实现。

实际上,策略和机制分离的本质就是进行标准化,也就是制定一套标准(提供机制),让使用者按照标准使用它(不同策略)。这样通过机制统一起来后,你就不用担心自己的实现不同而无法和别人完成配合了。

比如,Dubbo 框架就是为微服务架构模式下的不同服务提供了一种良好的 RPC 通信机制,不管你是会员服务还是商品服务,哪怕使用的系统实现策略完全不同,但大家只要按照协议约定进行 RPC 调用即可完成服务的复用。

再比如,Spring 其实就是将创建 Bean 和管理 Bean 的生命周期做了抽象和封装,形成了一种统一的机制。至于你想要创建什么具体类型的对象以及如何使用对象(策略),它并不用关心。

所以说,在架构设计上,进行策略和机制的分离才能让关注点得到有效的分离,不然最后会因为关注点混杂过多,导致系统越来越无法修改和维护。

2、技巧二:在编码实现上,做到使用和创建分离

下面再重点分析一个看似简单却直击本质的关注点分离,这也是一个经常使用却常常被忽略的关注点,重要性不亚于封装、多态和继承,即实体的实例化(创建)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱娃哈哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值