四种代码结构:按层封装,按功能封装,按组件封装,端口与适配器
实现客户查看订单状态的用例,按上面四种结构进行设计如下:
按层封装:
在这种简单的设计中,把代码分成三层:Web, 业务逻辑,持久化层,每一层都只能对下层有依赖关系。
客户发出查询请求,Web层负责接受并处理Web请求,并把请求交给下面的业务逻辑来处理,最后访问持久层来获取订单的信息。
OrderController: 负责处理Web请求
OrderService: 订单相关业务逻辑的接口
OrderServiceImpl: 订单服务的具体实现
OrdersRepository: 访问订单持久信息的接口
JdbcOrderRepository: 持久信息访问接口的实现
这种设计适合项目初期,随着规模扩大,三层结构已经不够了,需要进一步模块化。
还有一个问题是,这种分层是按技术来分层的,无法体现业务领域信息,比如两个都采用的分层结构的不同业务领域的代码,它们的相似程度极高,都是这三层。
按功能封装
在这种切分方式中,把所有的类型放到相同的包里,以业务概念来命名,在上层看来,下面的代码与业务领域相关了。
端口和适配器
内部区域(domain)包含了所有的相关业务领域的概念,外部区域(infrastructure)包含了与外界交互的功能(UI,数据库等),特别注意的是,外部区域是作为内部的插件来使用的,只能外部依赖内部,不能反过来。内部代码都应该用相关的业务领域语言来描述。比如,在业务领域中讨论的是Orders,而不是OrdersRepository.
外部区域中要注意不要使其中一个模块不经内部而直接调用另一个外部模块的功能。
如Web直接调用数据库的功能。(而没有经过内部控制)
按组件封装
把上面端口和适配器中的业务逻辑和持久化代码放在一起就是一个可独立部署的单元了,也就是组件.
其实上面四种设计,只看类接口间的关系,它们的代码是差不多的,依赖关系都是相同的,可以比较一下,不同的是封装的思想等的差别
包内访问属性设置为protected, public越小,潜在的依赖关系就越少,包外就不能直接调用,等于使用了编译器来维护设计原则了
参考:《clean architecture》