一、引言
分离关注点是我们经常听到的一个词汇,一说到分离关注点一般情况下有两种场景立即浮现在我们的眼前:一是分层;二是面向接口编程。这两个都只是分离关注点的具体实现,但并不是分离关注点的本质思想。分离关注点本身包含三层含义:一是如何分离; 二是关注点是什么;三是关注点如何实现的。本文就是围绕这三点进行阐述,结合自己的想法探讨一下分离关注点的实践。
关注点分离是面向对象的程序设计的核心概念。 分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用 (将针对特定领域问题代码抽象化成较少的程式码,例如将代码封装成function或是class),业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在在整个应用程序中的变动就可以很好的管理起来。 [1]
二、关注点是什么
之前听到一句话不变的是流程,变的是实现细节,当时好像懂了这句话,其实字面意思相信大家都懂,但少深入了一步。大部分业务需求,都是在做变的部分,如果不变也就没有业务需求了,变化的东西是什么?找到这个就是我们的关注点。
从软件设计上看,我们都是在实践找关注点是什么,分层只是实践关注点的一种。常见的有应用层、业务层、领域层、资源层等,每一层关注的东西是不一样的:应用层关注的是展示的多样性、交互的体验性;业务层关注的是业务流程的编排;领域层关注的是核心业务模型,更好的支撑业务;资源层关注的是数据存取。
从分层出发,往上抽象,就是4个字:单一职责。很久之前的软件设计原则只有两条:单一职责和开闭原则,它们影响了15年之久后陆续有其它的一些设计原则提出,后续的设计原则是上面两条原则进一步的补充和阐释。
从单一职责的角度,我们可以产出具体的方法实践出来。大概可以纵向和横向两个角度出发:纵向是具有依赖的;横向是水平可替换的。如何讲,分层就是纵向考虑的,每个层的职责不一样,但层与层之间有相互关联;接口实现是横向的,接口的实现是可替换的。
关注点其实很有意思,它看待的角度是不一样的,拿面向接口来说,接口本身的关注点是能做什么,接口的实现关注点是如何做的问题。我们在学习面向对象时,首先会讲到封装,讲封装最低层次就是讲封装私密性(数据保护);中层次就是对象功能的封装;高层次就是封装的关注点有哪些。面向对象的三大特性继承和多态都是为了封装服务的。
三、如何分离关注点
小到一个函数,大到一个类,再或者是一个包,甚至更大的是一个层,都可以看作是一个关注点,关注点常见划分的手段有两种:功能(职责)和业务语义。平时说的边界也是在分离各自己的关注点,划分边界也是体现了单一职责。
业务语义在领域建模中经常使用到,根据业务语义进行拆分,不同的对象放在不同的域内,如有订单域、商品域、交易域、结算域等等,它们的业务含义是不一样的。
功能划分是给对象分配职责,到底这个功能要放在哪里,GRASP给出一些模式可以参考。
到这里,分离关注点总的思路可以归结两点:拆分+归类,这两点是人认识事物重要的思维模式。如何拆分也可以按照功能和业务语义进行拆分,归类是在拆分的基础上做合并和抽象,哪些要放在一起,哪些是具有层次依赖的,这些最终是要形成一个整体。架构中的架字,你看它是怎么写的,一个加和木,架构之前说的是建筑行业(主要是以木头为主),多个木头加在一起就是架。所以谈软件架构,一定是有两部分的:"木"是什么、如何"架"。
四、关注点的实现
4.1 面向接口编程
这个是最简单理解的,接口关注的是能做什么;接口的实现关注的是如何做的问题。
4.2 配置文件
一说到反射这个大家都不陌生,可以把具体的实现写在配置文件里,像数据库的驱动、连接都可以写在配置文件里。只关注有数据库的服务,不关注具体的数据库是什么。
4.3 工厂模式
工厂模型也能实现关注点分离,工厂类帮我们管理了对象。
4.4 默认约定
默认约定大于配置是现在流行的做法,它本质来讲和配置文件没有什么太大的区别。
五、关注点开放
在业务的同学会发现需求永远是做不远的,来滴滴半年了,现在总结业务需求最多的是什么,把它归类思考,会发现有共性的。刚好昨天老大讲了我们是在中台的,要深入思考我们的核心能力是什么,并不是忙忙碌碌地做需求,每个需求背后有它的本质内容,要提供共性的功能。听了之后,一下子想到了好多。关注点开放是将业务会变的部分开放出去,收业务方自己去做,我们只做核心的功能。如何实现,画一张图表示。
变化?前置条件检查会变,数据处理会变,但什么不会变,就是核心业务处理不会变。所以完全可以把前后抽象出一个接口出来,具体的实现由业务方去实现,我们要提供的核心能力就是解析出业务方写的代码。在典型的具有模板结构中可以应用此法。
六、总结
本文提到分离关注点的一些想法,重点是如何发现关注点和关注点的实现,最后提出关注点开放的思路去解决业务上的一些问题。