项目模式(三)—— 分散的自组织模块
• 27 October 2019
应用场景
项目模块组成比较容易划分,接口不算复杂,每个模块可以用一个单例去表示的。每个模块中有很多种实现方法和配合方案,至于如何选择则通过配置决定。
不适合
- 无法使用单例承载的模块组织架构。也就是说,其他模块希望平行调用某个模块中的很多平行的方法。这种不适合使用这种松散耦合结构。
实现
.
├── project_name
├── module1
│ ├── base.py
│ ├── implementation_1.py
│ ├── implementation_2.py
│ └── __init__.py
├── module2
│ ├── base.py
│ ├── implementation_1.py
│ ├── implementation_2.py
│ └── __init__.py
- 在每个module中仅
__init__
作为引出的结构。其他模块不要访问其内部结构。 - 模块内部
base.py
(或使用某种有意义的名字)定义各种子模块(一般就是数据结构和一个核心类接口) __init__.py
中导出抽象层(数据结构+单例的类),注意抽象层命名。尽量不要使用 Base, Abstract 字样。__init__.py
还要导出一个工厂方法(可以lazy load)、或直接导出某个对象。在这个工厂方法中,可以无参数的构造某个对象,这个对象的构造需要使用哪个子类,需要哪些参数,都应由模块从配置中读取获得。
分析
-
这种方法从功能上来说,非常类似大工厂模式。每个工厂是一种配置组,通过不同的配置组去实现不同的功能组合。但是工厂模式如果用在此处有几个问题:
- 工厂是类,也就是代码,主要用在代码内部的实现。功能较重,可读性差,切换配置还需要重写工厂,不适合作为配置
- 一般配置都是相互无关的,个配个的,组合起来都能使用,和工厂这种产生组件的不一样。
- 工厂耦合了所有类的构造方式。而我们希望在每个模块里面建立自有的工程去生产该模块的产品(类似一个车间)。最终进行组合。
一些实现上的方案
-
堆叠项,对于一些模块,我们定义的是其中一步子任务的过程,而这种过程又是可以叠加的。那么有两种设计方式将多例转化为单例。
- 装饰器模式:将某种基操定义在模块顶层,具体操作定义为装饰器,用以装饰顶层操作。
- 堆叠项:设置一个特殊的操作,这个操作的输入是其他操作的组合,在项内解决如何综合结果的问题(Stack-Embedder/ Stack-processor 等)。
- 由于解决了依赖问题,每个模块可以认为是一个项目,可以递归的去构造项目(和配置)
- 和抽象工厂模式的兼容性:对于一些需要临时参数构造的类,可再使用抽象工厂进行包装。让模块返回的单例类为工厂,其他类通过这个工厂的基类去构造其想要的东西。