软件架构设计--“层间解耦和API接口设计”

1 软件架构设计之“层间解耦和API接口设计”
1)北向接口设计本质就更大系统的架构设计的一部分。
2)接口设计需要解决耦合与依赖的问题,系统间接口更是如此。
3)接口与实现分离、控制反转、依赖倒置是实现层间解藕的几个方式。

=======================
软件架构设计之“层间解耦和API接口设计”
钟振 00112298,2013-11-11
2 1 概述
“分层模式”是一种最常用的软件架构设计模式,采用分层模式时,要求层间低耦合,并且一般要求上层可调用下层服务、但不允许下层调用上层。那么当系统有这种需求(下层调用上层)时,应该如何设计呢?
本文主要参考[1] 文章,保留最精华的内容、补充部分方法和自己的理解、忽略“依赖注入”(有点晦涩),可结合[1]阅读本文。
其中“下层调用上层”的需求主要在“控制反转”一节给出解决方案。

3 2 接口和实现分离
4 2.1 面向过程的实现:函数库(函数调用)

5 2.2 面向对象的实现:类库(聚合关系)

6 3 依赖倒置(Dependency Inversion Principle)
7 3.1 原则说明
第一种描述([3]):
A. 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。
  B. 抽象不能依赖于具象,具象依赖于抽象。
第二种描述:
要针对接口编程,不要针对实现编程
8 3.2 解决方法一:类库设计者定义抽象接口(下层定义接口并实现)
当类库设计者难以和客户深入合作时,或者类库同时提供给很多客户使用时,这种方式比较合适。

9 3.3 解决方法二:调用方定义抽象接口(上层定义接口、下层实现)
如果是同一系统内的设计,优先使用方法二。这种方法也是面向对象设计推荐的方法。
10 3.3.1 Martin Flower给的例子

通常三层架构如上图(a);
经常需要引入一个Mapper层用于Domain/DB之间解耦具体数据映射方式,因此Mapper要依赖于Domain/DB,如(b)图;
但是,Domain怎么读写数据到DB呢?如果Domain依赖于Mapper则出现了“循环依赖”,这是一种很不好的设计。

由Domain层定义一个 Mapper Interface 接口,由Database层实现这个接口,则可以解决上述问题。

如果想简化类设计,可以把接口直接合入Domain层中(上图是合入Store类)。
11 3.3.2 Robert Martin给的例子
下图是一个典型的三层设计模式:

下图是经过依赖倒置重构后的架构:

12 4 控制反转
13 4.1 一个反面的例子

这是一个典型的双向依赖关系。这种双向依赖关系有一个非常严重的缺陷:由于GUI框架调用了应用程序中的某个特定函数(MyWindowProc), GUI框架根本无法独立存在;换一个新的应用程序,GUI框架多半就要做相应的修改。
14 4.2 解决方法一:面向过程设计中的“回调函数机制”

15 4.3 解决方案二:面向对象设计中的“模板方法模式”
16 4.3.1 王咏武给的例子

17 4.3.2 Craig Larman给的例子

18 4.4 解决方案三:面向对象设计中的“观察者模式”
19 4.4.1 Craig Larman给的例子

20 4.5 解决方案四:嵌入式软件中的“中断模式”
通过硬件中断主动上报事件,具体例子略。
21 5 参考资料
[1] 王咏武,《向依赖关系宣战——依赖倒置、控制反转和依赖注入辨析》,《程序员》杂志2005年1月
[2] Martin Flower,《Reducing Coupling》,2001,http://www.martinfowler.com/ieeeSoftware/coupling.pdf‎
[3] Robert Martin,《Agile Principles, Patterns, and Practices in C#》,2006
[4] Craig Larman,《Applying UML and Patterns》,2004
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值