如何组织和加载基于可配置属性的包?

时间:2016-09-22 09:16:45

标签: refactoring smalltalk configuration-management code-cleanup

我正在使用的系统可以使用不同的布尔属性进行配置。不同配置的理论最大值为2^n,其中n是此类属性的数量。

有一个与生产代码分离的配置工具,它使用布尔表达式来选择加载哪些代码包。 此工具包含一个类,用于定义isWithX等方法或更复杂的方法,如isWithXwithoutYwithZ。 包基本上是一个类扩展列表,用于定义或重新定义某些方法定义。 今天,这些包的名称类似于myPackageWithAWithoutBwithCwithDwithoutE

由于布尔配置属性的数量不断增加,不同包的数量和名称的大小变得越来越荒谬,我们无法一直看到它们的名字。 还有很多代码重复。

编辑:由于生产代码无法访问可配置属性,现在问题仅限于这些问题:

  • 每个包和每个功能的包名列表
  • 有多少种方法以及如何命名它们

现在,包名称列表基本上是所有不同的名称组合,如下所示:myPackageWithAWithoutBwithCwithDwithoutE,除了那些没有特定于我们需要实现的配置的行为的那些。

现在每个包和每个功能:每个包1个方法,包含功能名称。

2 个答案:

答案 0 :(得分:3)

我无法告诉您如何解决您的具体问题,因此我将与您分享一些可能有助于您开始寻找实际适用于您的设计的提示。

考虑配置对象的层次结构:

ConfigurationSettings
  ApplicationSettings
  UserSettings
  DisplaySettings
  ...

抽象类ConfigurationSettings提供读取/写入属于任何特定部分的设置的基本服务。层次结构允许更简单的命名约定,因为选择器可以在不同的子类中重新实现。

ApplicationSettings子类扮演不同的角色:它注册其registry实例变量中的所有部分,Dictionary,其中键是部分名称,值是相应的子类实例:

ApplicationSettings current register: anEmailSettings under: `Email`

抽象类提供了读写设置的基本服务:

settingsFor: section 
settingAt: key for: section
settingAt: key for: section put: value

子类使用这些服务来访问单个设置并实现客户端所需的逻辑,以测试当前配置ishassupports等特定功能或组合。这些更具体的方法是根据更基本的settingAt:for:实现的。

当一个新包注册它自己的子类时,它的测试方法可用如下:

self <section>Settings isThisButNotThat

例如,

emailSettings
  ^(ApplicationSettings current for: 'Email') isThisButNotThat

和任何其他部分类似。正如我上面提到的,子类中的除法将允许您使用更简单的选择器隐式引用该部分(#isThisButNotThat而不是#isEmailThisButNotThat)。

另一个对于支持用户修改设置的“应用/取消”对话框很重要的功能由两种方法提供:

 ConfigurationSettings >> #readFrom:

 ConfigurationSettings >> #writeOn:

因此,当您打开显示设置的GUI时,您不会在当前实例上打开它,而是在它们的副本上打开它

settings := ApplicationSettings new readFrom: ApplicationSettings current.

然后在GUI中将此副本呈现给用户。如果用户取消该对话框,您只需忘记该副本。否则,您可以通过这种方式应用更改:

settings writeOn: ApplicationSettings current

这两项服务的实施遵循一个简单的模式:

ApplicationSettings >> readFrom: anApplicationSettings
  registry keysAndValuesDo: [:area :settings | | section |
    section := anApplicationSettings for: area.
    settings readFrom: section]

ApplicationSettings >> writeOn: anApplicationSettings
  registry keysAndValuesDo: [:area :settings | | settings |
    section := anApplicationSettings for: area.
    settings writeOn: section]

答案 1 :(得分:0)

我不完全了解您问题的所有方面,但也许您可以使用动态方法。例如,您可以覆盖#doesNotUnderstand:来解析发送到配置的选择器并提取包名称:

doesNotUnderstand: aMessage
| stream included excluded  |
"parse selectors like #isWithXwithoutYwithoutZ"
stream := (#isWithXwithoutYwithoutZ allButFirst: 6) asLowercase readStream.
included := Set new.
excluded := Set new.
[ stream atEnd ] whileFalse: [
    (stream peek: 3) = 'out'
        ifTrue: [
            stream next: 3.
            excluded add: (stream upToAll: 'with') ]
        ifFalse: [ included add: (stream upToAll: 'with') ] ].

然后,您需要的是更多代码来生成包的列表(我希望)。