11.1 如何建造一个城市
城市能运转,因为它演化出恰当的抽象等级和模块,好让个人和其所管理的“组件”即便在不了解全局时也能有效地运转。
11.2 将系统的构造与使用分开
首先,构造与使用是非常不一样的过程。
软件系统应将起始过程和起始过程之后的运行时逻辑分离开,在起始过程中构建应用对象,也会存在互相缠结的依赖关系。
每个应用程序都该留意起始过程。
11.2.1 分解main
将构造与使用分开的方法之一是将全部构成过程搬迁到main或被称之为main的模块中,设计系统的其余部分时,假设所有对象都已正确构造和设置。
11.2.2 工厂
当然,有时应用程序也要负责确定何时创建对象。
11.2.3 依赖注入
有一种强大的机制可以实现分离构造与使用,那就是依赖注入(Dependency Injection,DI)。控制反转(Inversion of Control,IoC)在依赖管理中的一种应用手段。
11.3 扩容
“一开始就做对系统”纯属神话。我们应该只去实现今天的用户故事,然后重构,明天再扩展系统、实现新的用户故事。这就是迭代和增量敏捷的精髓所在。测试驱动开发、重构以及它们打造出的整洁代码,在代码层面保证了这个过程的实现。
与物理系统相比,软件系统比较独特。软件系统的架构可以递增式地增长,只要我们持续将关注面恰当地切分。
横贯式关注面
原则上,你可以从模块、封装的角度推理持久化策略。但在实践上,你却不得不将实现了持久化策略的代码铺展到许多对象中。我们用术语横贯式关注面(Cross-Cutting Concern)来形容这类情况。
面向方面编程(aspect-oriented programming,AOP)是一种恢复横贯式关注面模块化的普适手段。
在AOP中,被称为方面(aspect)的模块构造说明了系统中哪些点的行为会以某种一致的方式被修改,从而支持某种特定的场景。这种说明是用某种简洁的声明或编程机制来实现的。
11.4 Java代理
Java代理适用于简单的情况。JDK提供的动态代理仅能与接口协同工作。对于代理类,你得使用字节码操作库。
11.5 纯Java AOP框架
在Spring中,你将业务逻辑编码为旧式Java对象。POJO自扫门前雪。它在概念上更为简单、更易于测试驱动,相对简单,也较易于保证正确地实现相应的用户故事,并为未来的用户故事维护和改进代码。
11.6 AspectJ的方面
通过方面来实现关注面切分的功能最全的工具是AspectJ语言,它提供“一流的”将方面作为模块构造处理支持的Java扩展。
11.7 测试驱动系统架构
最佳的系统架构由模块化的关注面领域组成,每个关注面均用纯Java(或其他语言)对象实现。不同的领域之间用最不具有侵害性的方面或类方面工具整合起来。这种架构能驱动测试,就像代码一样。
11.8 优化决策
拥有模块化关注面的POJO系统提供的敏捷能力,允许我们基于最新的知识做出优化的、时机刚好的决策。决策的复杂性也降低了。
11.9 明智使用添加了可论证价值的标准
有了标准,就更易复用想法和组件、雇用拥有相关经验的人才、封装好点子,以及将组件连接起来。不过,创立标准的过程有时却漫长到行业等不及的程度,有些标准没能与它要服务的采用者的真实需求相结合。
11.10 系统需要领域特定语言
领域特定语言允许所有抽象层级和应用程序中的所有领域,从高级策略到底层细节,使用POJO来表达。
11.11 小结
系统也应该是整洁的。
在所有抽象层级上,意图都应该清晰可辨。
无论是设计系统还是单独的模块,别忘了使用大概可开展工作的最简单方案。