在我参与多年的项目中,我逐渐发展出一种被证明对我非常有用的设计模式。我有时觉得我应该对它有点福音派,但如果我尝试并发现它只是我某人的旧帽子版本,我会有点尴尬。我已经挖掘了设计模式徒劳地寻找它,我没有遇到任何其他人谈论它,但我的搜索并不详尽。
核心思想是拥有一个代理对象来管理一组定义对象,每个定义对象构成一些复杂属性的可能值。例如,您可能拥有CarType,Plane和Generator类,它们都具有EngineType。 Car不存储自己的EngineType对象,它存储某种类型的引用键,表示它具有的引擎类型(例如整数或字符串ID)。当我们想要查看EngineType的属性或行为时,比如说WankelEngine,我们要求EngineTypeBroker单例对象获取WankelEngine的定义对象,并将其传递给引用键。这个对象封装了有关EngineTypes的有趣内容,可能只是一个属性列表,但也可能将行为加载到它上面。
所以它的促进是一种共享的,松散耦合的聚合,其中许多汽车可能有一个WankelEngine但只有一个WankelEngine定义对象(并且EngineTypeBroker可以替换该对象,利用松散耦合到增强的运行时态射)。
我使用它时这个模式的一些元素(继续使用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!";
}
}
那么,那里有名字吗?
答案 0 :(得分:2)
信不信由你。我今天早上想的是同样的事情。
之前我使用过这种模式,但我从来没有找到它的参考,也不知道如何命名。
我认为是一种“Keyed”单例,其中实例存储在某处,并且使用密钥获取它们。
我最后一次使用它是从不同来源检索数据。
我有大约50个数据库表(使其成为10)并且我有一个前端“表”,其中显示数据,但数据可能来自任何这些来源,每个都需要不同的逻辑(查询,连接,键等)
这个前端是“可配置的”,所以我不知道要显示哪些值以及哪些不会显示。
解决方案是将columnName(在前端)作为键,并获取正确的实例以创建正确的查询。
它在开头安装在哈希映射中,之后从数据库表中检索。
代码是这样的:
class DataFetcher {
abstract Object getData( Object id );
}
class CustomerNameDataFetcher extends DataFetcher {
Object getData( Object customerId ) {
// select name from customer where id = ?
}
}
class CompanyAdressDataFetcher extends DataFetcher {
Object getData( Object customerId ) { // don't ask why.
// select name from company , customer where customer.co = company.co and cu = ? etc.
}
}
class ProductColor extends DataFetcher {
Object getData( Object x ) {
// join from customer to color, to company to season to a bunch of table where id = ?
}
// And the list goes on.
每个子类使用不同的逻辑。
在运行时,用户配置了它的视图,并选择他想要查看的内容。
当用户选择要查看的列时,我使用列名和Id来获取数据。
在类方法中,DataFetchers都安装在父类中(我不想为此设置一个separeate类)。
class DataFetcher {
abstract Object getData( Object id );
private static final Map fetchers = new HashMap();static {
fetchers.put("customer.name", new CustomerNameDataFetcher() );
fetchers.put("company.address", new CompanyAdressDataFetcher () );
fetchers.put("product.color", new ProductColor () );
...
}
public static DataFetcher getFetcher( String id ) {
return fetchers.get( id );
}
}
最后填写前端表我只是这样称呼:
伪代码
for each row in table
for each column in row
column.text = DataFetcher.getFetcher( column.id ).getData( row.id )
end
end
这是这样的吗?或者我误解了你的描述,而我的描述则完全不同。
最后我认为这被称为SingletonRegistry或类似的东西。我(可能)喜欢你,出于必要而创造了这个。机会是这是一种常见的模式。
答案 1 :(得分:2)
之前我使用过类似的模式,最常用的是游戏。我有一个WeaponDefinition和WeaponInstance类(不完全是那些名字)。 WeaponDefinition类(以及各种子类,如果我有不同类型的武器,例如近战与射弹)将负责跟踪该类型武器的全球数据(射速,最大弹药,名称等),并具有所有的逻辑。 WeaponInstance类(和子类)包含触发序列中的当前状态(用于比较火焰速率),当前弹药计数和指针(它可能是您的示例中的一个经理类的关键,但是对于WeaponDefinition来说,这似乎不是模式的要求。 WeaponInstance有一堆用于触发,重新加载等的函数,它们只调用WeaponDefinition实例上的相应方法,并将自身作为参数传递。这意味着WeaponDefinition的东西不会为游戏世界中的每个坦克/士兵/飞机重复,但它们都有自己的弹药计数等。
我不知道它叫什么,我不确定它与你所谈论的完全相同,但我认为它很接近。这绝对有用。
答案 2 :(得分:1)
听起来像GoF Builder,Prototype和对我来说可能是羽量级的组合。
答案 3 :(得分:1)
听起来像是各种各样的Flyweight(许多汽车共享一个WankelEngine)。但这有什么意义呢?大多数汽车都有发动机,但是它们中的许多汽车如何拥有相同的发动机实例?他们不会那么远。或者你是说很多车都有WankelEngine型发动机?更有意义的是。那么“WankelEngine定义对象”的用途是什么?它是一个工厂,正在构建该对象的味道并将它们传递给请求者?如果是这样,它听起来不像一个定义对象,听起来更像是一个工厂,它正在接受要构建的对象的参数并将该对象返回。
我确实在这里看到了一些很好的GoF练习,特别是你正在编写而不是继承(我的Car有一个引擎而不是我的Car的引擎是一个WankelEngine)。我希望我能完全回忆起这句话,但它就像“继承打破封装”和“赞成合成而不是继承”。
我很好奇这个问题解决了什么。我认为你增加了很多复杂性,我没有看到这种复杂性的需要。也许这是我不懂的语言特有的东西。
GoF的人确实讨论将模式组合成更大的模式,MVC尤其是三种其他模式的集合。听起来你已经做过类似的事情了。
答案 4 :(得分:1)
听起来有点像服务定位器,其中你的羽量重量被注册为单身人士。
答案 5 :(得分:-1)
你所拥有的是地图,即字典。通过将多个键映射到一个对象,您只需要有一个独特的扭曲。
为什么是地图:
您可以在以下位置找到实施: