重要且紧急 | 重要不紧急 |
---|---|
不重要但紧急 | 不重要且不紧急 |
对程序控制权的直接转移进行了限制和规范
对程序控制权的间接转移进行了限制和规范
对程序中的赋值进行了限制和规范
关注重点:功能性、组件独立性、数据管理
原本:系统行为决定了控制流,而控制流决定了源代码依赖关系
使用多态后:模块和接口在源代码上的依赖关系的方向和控制流是相反的
任何一个软件模块都应该只对某一类行为负责
!将服务不同行为者的代码进行切分
设计良好的计算机软件应该易于扩展,同时抗拒修改
组件遵守同一约定,以便相互替换
!任何层次的软件设计如果依赖了它并不需要的东西,就会带来意料之外的麻烦
高层策略性的代码不应该依赖实现底层细节的代码
DIP具体的编码守则:
软件复用的最小粒度应等同于其发布的最小粒度
将那些会同时修改、且为相同目的而修改的类放到一个组件中;反之,放到不同组件中
不要强迫一个组件的用户依赖他们不需要的东西
组件依赖关系中不应该出现环
打破循环依赖:
1.应用依赖反转原则(DIP)
2.创建新组件存放原本不同组件中互相依赖的类
依赖关系必须要指向更稳定的方向
一个组件的抽象化程度应该与其稳定性保持一致
一个系统的架构必须能支持其自身的设计意图
一个设计良好的软件架构可以让系统在构建完成之后立刻就能部署
一个设计良好的架构应该通过保留可选项的方式,让系统在任何情况下都能方便地做出必要的变更
一个系统可以被解耦成若干个水平分层——UI界面、应用独有的业务逻辑、领域普适的业务逻辑、数据库等
如果我们按照变更原因的不同对系统进行解耦,就可以持续地向系统内添加新的用例,而不会影响旧的用例
架构师们经常会钻进一个牛角尖——害怕重复
!看起来重复,但由于不同的变更速率和变更缘由,并不是真正的重复
!看起来类似的两个用例,复用同一段代码。但只是表面的类似,未来将它们分开会面临很大的挑战
源码层次 | 部署层次 | 服务层次
一个系统所适用的解耦模式可能会随着时间而变化,优秀的架构师应该能预见这一点,并且做出相应的对策
边界线应该画在那些不相关的事情中间:
❌由于GUI能直接看到,就很自然地把GUI当成了系统本身
I/O是无关紧要的
界面背后存在着一个模型——一套非常复杂的数据结构和函数,那才是系统真正的核心驱动力
系统的核心业务逻辑必须和其他组件隔离,保持独立,而这些其他组件要么是可以去掉的,要么是有多种实现的
这其实是单一职责原则(SRP)的具体实现,SRP的作用就是告诉我们应该在哪里画边界线
一般来说,低层组件被设计为依赖高层组件
上图中所有的依赖关系都指向了边界内部,它是该系统中最高层次的组件。这个架构将高层的加密策略与低层的输入/输出策略解耦,当低层策略发生变更时,不太可能会影响高层策略。
业务实体包含关键业务逻辑和关键业务数据,它与数据库、图形界面、第三方框架等内容无关。业务实体这个概念中应该只有业务逻辑,没有别的
用例描述一个特定的应用情景,更靠近系统的输入和输出,属于低层概念。而业务实体属于高层概念,并不会知道是哪个业务用例在控制它们。用例依赖于业务实体,而业务实体并不依赖与用例
源码中的依赖关系必须只指向同心圆的内层,即由低层机制指向高层策略
!任何内层圆中的代码都不应该牵涉外层圆中的代码(eg:函数名、类名、变量名等)
!不应该让外层圆中发生的任何变更影响到内层圆的代码
目的:帮助单元测试的编写者区分容易测试的行为和难以测试的行为
思路:将这两类成为拆分成两组模块或类,谦卑组包含难以测试的行为,另一组包含不属于谦卑对象的行为
视图->难以测试的谦卑对象->代码应该越简单越好
故:应只负责将数据填充到GUI上,而不应该对数据进行任何处理
展示器->可测试的对象
工作:从应用程序中接收数据,按视图的需要将这些数据格式化,以便视图将其呈现在屏幕上
将数据库获取的数据根据高层逻辑的需要格式化
将服务接口中接收的数据根据程序的需要格式化
!在每个系统架构的边界处,都有可能发现谦卑对象模式的存在,因为跨边界的通信肯定需要用到某种简单的数据结构,运用谦卑对象模式可以大幅提高整个系统的可测试性
服务边界并不能代表系统的架构边界,服务内部的组件边界才是
它们都是实现细节: