组件设计原则

随着软件代码规模的不断扩大,代码的维护成本越来越高,组件化势在必行,设计组件时应该考虑哪些问题?本文介绍了组件设计的六大原则。

随着软件代码规模的不断扩大,管理软件的复杂性,使软件容易扩展,确保业务和研发效率的敏捷性越来越重要。项目架构层面上,开闭原则告诉我们要将系统划分为一系列组件,组件之间的依赖关系按照层次结构进行组织,从而使得系统容易扩展。

大型软件系统中,一般将系统分层,比如基础组件层、业务逻辑层,数据持久层、服务层。横向上,一般也会根据业务、功能进行组件化。在组件化过程中,哪些类应该组合成一个组件?组件之间如何解耦?如何实现“高内聚,低耦合”?这些问题都是开发人员要谨慎考虑的问题。

SOLID设计原则主要关注类的设计,解决如何将数据和函数设计成类,以及如何将这些类链接起来成为程序的问题。
Robert C. Martin《架构整洁之道》 中,他提出了一些用于组件设计的原则,一共包括六个原则。
组件聚合指导我们应该将哪些类组合成一个组件,要考虑三个原则:复用/发布等同原则共同闭包原则共同复用原则
组件耦合帮助我们确定组件之间的相互依赖关系,要考虑三个原则:无依赖环原则稳定依赖原则稳定抽象原则

组件聚合

组件聚合是应该把哪些类应该被组合成一个组件?

复用/发布等同原则(The Reuse/Release Equivalence Principle, REP)

软件复用的最小粒度等同于其发布的最小粒度。

REP告诉我们,代码复用在组件这一级,可复用的组件中必须包含可复用的类,这些可复用的类以组件的方式发布给用户使用。从另外一个角度去考虑一个组件的内容,一个组件中的类要么都可以重用,要么都不是可重用的。

REP要求我们保持组件的重用粒度和组件的发布粒度一致。例如,两个组件A、B,如果其他组件总是一起使用组件A、B,而且这两个组件总是一起发布,那么这两个组件应该合为一个组件。组件中的类与模块必须是彼此紧密相关的

共同闭包原则(The Common Closure Principle, CCP)

应该将那些会同时修改、相同目的修改的类放在同一个组件中。另一方面,应该将不会同时修改,不会为了相同的目的而修改的类放在不同的组件中。

CCP原则告诉我们,如果一个应用中的代码需要同时、为统一目的发生修改,尽量让这种修改都集中在一个组件中,而不是分散在多个组件中。如果将这些更改分散在多个组件中,将增加软件发布、验证和维护工作量。
共同闭包原则不重视代码的复用性,例如,如果A和B组件共同依赖于C组件,而且A组件的变化经常伴随着C变更,按照CCP原则的要求,C组件应该要放入A组件中,同样C组件应该放入B组件中,这将会导致代码复用性降低。

对于大部分应用程序来说,可维护性的重要性要远远高于可复用性

共同复用原则(The Common Reuse Principle, CRP)

不要强迫一个组件依赖他们不需要的东西。

CRP原则是面向对象设计原则中接口分离原则的普适版本。CRP要求经常共同复用的类和模块放在同一个组件中,而不是紧密相连的类不应该放在同一个组件中。
一个组件中的类应该一起被复用,相反,如果你只用一个组件中的一部分类,那么应该把不用的类从组件中移除出去。
从另一个方面讲,在一个组件中不应该包含太多不同类型的类,不要把一些完全不相干的类放在一个组件中,这样会导致组件的职责过重,从而增加修改和发布的频率。

哪个原则更重要?

你可能已经意识到,上述三个原则是相互竞争的。REP和CCP是粘合性原则,告诉我们哪些类要放在一起,这会让组件变得更大。CRP是排除性的原则,不需要的类要从组件中移除出去,这会使组件变小。软件架构师的重要任务就是在这三个原则之间做出均衡

三大原则张力图

只关注两个方面,而忽略另一个方面会引发一些问题:

  1. 只关注REP和CRP将会导致一个功能会拆分为更多组件,每次需求变更会导致太多的组件变更。
  2. 只关注REP和CCP将会导致每个组件规模很庞大,改动一个小点,就会导致组件更新版本,从而使得组件频繁发布。
  3. 只关注CCP和CRP将会导致不关注组件的复用性,使得组件复用困难。

如何进行权衡?
Bob大叔建议我们,要在上述三角区域中定位一个最适合目前研发团队状态的位置,同时不停调整。
在项目早期,CCP原则会比REP原则更重要,因为这一阶段开发速度要比复用性更重要,这个时候可以牺牲复用性,换取开发速度。
随着项目成熟,其他组件之间产生产生更多依赖,项目重心就逐渐会向三角区域的左侧滑动,更加重视复用性。

也就是说,要根据项目的开发时间成熟度不断变动、不断演化的,与项目本身的功能关系很小。

组件耦合

如何管理组件之间的依赖关系?

无依赖环原则 (Acyclic Dependencies Principle,ADP)

组件依赖关系图中不应该出现环

环形依赖关系使得一个组件修改之后的影响范围将变得非常大,环中任何一个组件发生变更,会对环上每一个组件产生影响,进而导致对环上组件依赖的其他组件产生影响,导致系统难以升级和维护。

如何打破依赖循环? 有两种机制可以消除环形依赖关系:1)使用依赖反转原则 2)创建一个新组件
下面举例说明,在这个例子中三个组件Interactors、Authorizer、Entities三个组件形成环形依赖关系。

循环依赖

1)使用依赖反转原则

使用依赖反转原则

步骤:

  1. 分析发现,Entities组件中User使用到Authorizer组件中的认证Permission功能
  2. 把User调用Authorizer组件中的认证Permission抽象成为一个接口,User依赖这个接口,而不是依赖于Authorizer
  3. Authorizer实现了Permission接口(是Permission的具体类),于是Authorizer依赖于Permission接口
  4. Authorizer依赖于Entities组件,实现了依赖反转,打破了依赖循环。

2)创建新组件


创建新组件

1、把Entities组件中User使用到Authorizer组件中的认证Permission功能单独拆分出来,形成新的组件Permissions。
2、Entities和Authorizer共同依赖于新的组件,打破了依赖循环。

稳定依赖原则(The Stable Dependencies Principle,SDP)

依赖关系必须指向更稳定的方向

如何衡量一个组件的稳定性?
不稳定性指标:I = (对别的组件依赖个数)/ (对别的组件依赖个数 + 别的组件对自己依赖个数)

每一个组件的I指标必须大于其依赖组件的I指标。

稳定抽象原则(The Stable Abstractions Principle,SAP)

一个组件的抽象化程度应该与其稳定性保持一致。

组件的抽象化程度 A = 组件中抽象类和接口的数量/组件中具体类的数量。

  1. 稳定的组件应该是抽象的,应该由接口和抽象类组成。
  2. 一个不稳定的组件应该包含具体的实现代码。
  3. 依赖关系应该指向更加抽象的方向。

总结

本文介绍了组件设计要考虑的原则,首先,要考虑应该把哪些类应该被组合成一个组件,组件太大和太小都会有不同的问题,组件聚合原则告诉我们设计组件时要考虑的原则,以及如何根据项目的开发时间和成熟度对这些原则进行权衡。组件耦合考虑的是如何管理组件之间的依赖关系,减小组件之间的耦合,组件依赖要考虑的问题。从组件聚合和组件耦合全面分析,可以设计出"高内聚、低耦合"的组件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354