3

在我参与多年的一个项目中,我逐渐形成了一种被证明对我非常有用的设计模式。有时我觉得我应该对它有点福音,但如果我尝试并发现它只是我对某人旧帽子的版本,我会有点尴尬。我翻遍了设计模式来寻找它是徒劳的,我还没有遇到其他人谈论它,但我的搜索并不详尽。

核心思想是拥有一个管理一组定义对象的代理对象,每个定义对象构成一些复杂属性的可能值。例如,您可能有 Car、Plane 和 Generator 类都具有 EngineType。Car 不存储自己的 EngineType 对象,它存储了某种类型的引用键,用于说明它拥有的引擎类型(例如整数或字符串 ID)。当我们想查看 EngineType 的属性或行为时,比如 WankelEngine,我们向 EngineTypeBroker 单例对象询问 WankelEngine 的定义对象,并将引用键传递给它。该对象封装了有关 EngineTypes 的所有有趣信息,可能只是一个属性列表,但也可能将行为加载到它上面。

所以它促进的是一种共享的、松散耦合的聚合,其中许多汽车可能有一个 WankelEngine 但只有一个 WankelEngine 定义对象(并且 EngineTypeBroker 可以替换该对象,利用松散耦合增强运行时态射)。

我使用该模式的一些元素(继续以 EngineType 为例):

  1. 始终存在 IsEngineType(x) 和 EngineType(x) 函数,分别用于确定给定值是否是 EngineType 的有效引用键和检索与引用键对应的 EngineType 定义对象。
  2. 对于给定的 EngineType,我总是允许多种形式的引用键,总是至少是一个字符串名称和定义对象本身,通常不是整数 ID,有时是聚合 EngineType 的对象类型。这有助于调试,使代码更灵活,并且在我的特定情况下,相对于旧实践,可以缓解许多向后兼容性问题。(在这个项目的上下文中,人们过去做这一切的常用方法是为 EngineType 可能具有的每个属性定义哈希,并通过引用键查找属性。)
  3. 通常,每个定义实例都是该定义类型的通用类的子类(即 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!";
    }

}

那么,有这个名字吗?

4

6 回答 6

2

单例注册表

信不信由你。今天早上我也在想同样的事情。

我以前使用过这种模式,但我从未找到它的参考资料,也不知道如何命名它。

我认为是一种“键控”单例,其中实例存储在某处,并使用键获得。

我最后一次使用它是从不同来源检索数据。

我有大约 50 个数据库表(使其成为 10 个)并且我有一个前端“表”,其中要显示数据,但数据可能来自任何这些来源,并且每个来源都需要不同的逻辑(查询、连接、键, ETC。 )

这个前端是“可配置的”,所以我不知道要显示哪些值,哪些不显示。

解决方案是以 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 都安装在类方法中的父类中(我不想为此有一个单独的类)。

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 或类似的东西。我(可能)喜欢你,出于需要创造了这个。很有可能这是一种常见的模式。

于 2008-12-30T23:09:40.993 回答
2

我以前使用过类似的模式,最常见于游戏中。我会有一个 WeaponDefinition 和 WeaponInstance 类(不完全是那些名字)。WeaponDefinition 类(以及各种子类,如果我有不同类型的武器,例如近战与射弹)将负责跟踪该类型武器的全局数据(射速、最大弹药、名称等)并具有所有的逻辑。WeaponInstance 类(和子类)包含射击序列中的当前状态(用于比较射速)、当前弹药计数和一个指针(它可能是您的示例中管理器类的一些键,但是这似乎不是模式的要求)到武器定义。WeaponInstance 有很多用于开火、重新装弹等的函数,只需在 WeaponDefinition 实例上调用适当的方法,将自身作为参数传递。这意味着 WeaponDefinition 的东西不会被游戏世界中的每个坦克/士兵/飞机复制,但它们都有自己的弹药数量等。

我不知道它叫什么,我不确定它和你说的完全一样,但我认为它很接近。这绝对有用。

于 2008-12-31T00:28:30.863 回答
1

在我看来,这听起来像是 GoF Builder、Prototype 和 Featherweight 的组合。

于 2008-12-30T22:38:22.257 回答
1

这听起来像是多种 Flyweight(许多汽车共用一个 WankelEngine)。但这有什么意义呢?大多数汽车都有引擎,但它们中怎么会有相同的引擎实例呢?他们不会走那么远。或者你的意思是很多汽车都有 WankelEngine 类型的发动机?假设这更有意义。那么“WankelEngine定义对象”有什么用呢?是否是一个工厂,它正在构建该对象的风格并将它们传递回请求者?如果是这样,它听起来不像是一个定义对象,听起来更像是一个工厂,它接受对象的参数来构建并返回该对象。

我确实在这里看到了一些好的 GoF 实践,特别是您正在编写而不是继承(我的汽车有一个引擎,而我的汽车的引擎是 WankelEngine)。我希望我能准确地回忆起这句话,但它类似于“继承打破封装”和“偏好组合而不是继承”。

我很好奇这个解决了什么问题。我认为您增加了很多复杂性,我认为不需要这种复杂性。也许这是我不理解的特定于您的语言的东西。

GoF 的人确实讨论了将模式组合成更大的模式,特别是 MVC 是其他三种模式的集合。听起来你做过类似的事情。

于 2008-12-30T22:57:03.530 回答
1

这听起来有点像服务定位器,其中您的轻量级被注册为单例。

于 2014-05-07T18:07:59.763 回答
-1

你有一张地图,也就是字典。通过将多个键映射到一个对象,您只需对其进行独特的改动。

为什么是地图:

  • 保留一把钥匙
  • 使用键从某些数据结构中查询值。

您可以在以下位置找到实现:

  • STL(包括:地图)
  • Java(导入:java.util.Dictionary)
于 2011-12-12T06:00:47.097 回答