在我参与多年的一个项目中,我逐渐形成了一种被证明对我非常有用的设计模式。有时我觉得我应该对它有点福音,但如果我尝试并发现它只是我对某人旧帽子的版本,我会有点尴尬。我翻遍了设计模式来寻找它是徒劳的,我还没有遇到其他人谈论它,但我的搜索并不详尽。
核心思想是拥有一个管理一组定义对象的代理对象,每个定义对象构成一些复杂属性的可能值。例如,您可能有 Car、Plane 和 Generator 类都具有 EngineType。Car 不存储自己的 EngineType 对象,它存储了某种类型的引用键,用于说明它拥有的引擎类型(例如整数或字符串 ID)。当我们想查看 EngineType 的属性或行为时,比如 WankelEngine,我们向 EngineTypeBroker 单例对象询问 WankelEngine 的定义对象,并将引用键传递给它。该对象封装了有关 EngineTypes 的所有有趣信息,可能只是一个属性列表,但也可能将行为加载到它上面。
所以它促进的是一种共享的、松散耦合的聚合,其中许多汽车可能有一个 WankelEngine 但只有一个 WankelEngine 定义对象(并且 EngineTypeBroker 可以替换该对象,利用松散耦合增强运行时态射)。
我使用该模式的一些元素(继续以 EngineType 为例):
- 始终存在 IsEngineType(x) 和 EngineType(x) 函数,分别用于确定给定值是否是 EngineType 的有效引用键和检索与引用键对应的 EngineType 定义对象。
- 对于给定的 EngineType,我总是允许多种形式的引用键,总是至少是一个字符串名称和定义对象本身,通常不是整数 ID,有时是聚合 EngineType 的对象类型。这有助于调试,使代码更灵活,并且在我的特定情况下,相对于旧实践,可以缓解许多向后兼容性问题。(在这个项目的上下文中,人们过去做这一切的常用方法是为 EngineType 可能具有的每个属性定义哈希,并通过引用键查找属性。)
- 通常,每个定义实例都是该定义类型的通用类的子类(即 WankelEngine 继承 EngineType)。定义对象的类文件保存在类似/Def/EngineType 的目录中(即WankelEngine 的类将是/Def/EngineType/WankelEngine)。因此相关的定义被组合在一起,类文件类似于 EngineType 的配置文件,但具有定义代码的能力(通常不会在配置文件中找到)。
一些简单的示例伪代码:
class Car {
attribute Name;
attribute EngineTypeCode;
object GetEngineTypeDef() {
return EngineTypeBroker->EngineType(this->GetEngineTypeCode());
}
string GetDescription() {
object def = this->GetEngineTypeDef();
return "I am a car called " . this->GetName() . ", whose " .
def->GetEngineTypeName() . " engine can run at " .
def->GetEngineTypeMaxRPM() . " RPM!";
}
}
那么,有这个名字吗?