类似于 是硬的编码文本都可以接受的吗?, 但我具体想的"魔术的琴弦"在这里。

在一个大项目,我们有一个表格的结构选择这样的:

Name         Value
----         -----
FOO_ENABLED  Y
BAR_ENABLED  N
...

(百)。

常见的做法是要求一个一般功能测试一个选项,是这样的:

if (config_options.value('FOO_ENABLED') == 'Y') ...

(当然,这同样的选择可能需要检查,在许多地方系统中的代码。)

当添加一个新的选择,我是在考虑增加一个功能隐藏"魔string"这样的:

if (config_options.foo_enabled()) ...

然而,同事还以为我去过分,并反对这样做,更喜欢强硬的编码的,因为:

  • 这就是我们通常做的
  • 这使它更容易看到什么时候上的调试代码

麻烦的是,我可以看到他们点!实际上,我们永远不会重新命名的选项,对于任何原因,所以有关的唯一优点我能想到的我的功能,编译器会赶上的任何错误就像fo_enabled(),但不是'FO_ENABLED'.

你怎么想?我错过了任何其他的优点/缺点?

有帮助吗?

解决方案

if (config_options.isTrue('FOO_ENABLED')) {...
}

限制你的硬盘编码Y检查到一个地方,即使这意味着编写一个包装类对于你的地图。

if (config_options.isFooEnabled()) {...
}

可能看起来好直到你有100配置的选择和100方法(所以这里你可以判断未来的应用程序的增长和需求,然后决定你的实现)。否则最好是有一类的静态串参数的名字。

if (config_options.isTrue(ConfigKeys.FOO_ENABLED)) {...
}

其他提示

如果我使用一串一次在代码,我一般不要担心它一定在某个地方。

如果我使用一串两次在代码我会 考虑 使这一恒定。

如果我使用一串三次在代码,我几乎肯定会使这一恒定。

我意识到这个问题是旧的,但它提出了在我的保证金。

AFAIC,这里的问题没有准确地识别,无论是在问题或问题的答案。忘记关于'harcoding串"或不行,一会儿。

  1. 该数据库有一个参考表、包含 config_options.PK是一串。

  2. 有两种类型的PKs:

    • 有意义的标识符,用户(和开发人员)参阅和使用。这些PKs应该是稳定的,他们可以依赖。

    • 毫无意义 Id 列的用户不应该看到,开发人员必须意识到,代码左右。这些不能依赖。

  3. 这是普通的,正常的,编写代码使用的绝对值的一个有意义的PK IF CustomerCode = "IBM" ...IF CountryCode = "AUS" 等等。

    • 引用的绝对值毫无意义的PK是不可接受的(由于自动增量;差距正在改变;值被取代批发).
      .
  4. 你的参考表格的使用有意义的PKs。引用的那些字符串中码是不可避免的。隐藏的价值将使维护更加困难;代码已不再是文字;你的同事是对的。再加上还有其他冗余功能嚼的周期。如果有错误,在文字的,你很快就会发现,在开发的测试,很久以前UAT.

    • 数以百计的功能,对数以百计的文字是荒谬的。如果你做实施一个函数,然后正常化的代码,并提供一个单一的功能,可以用任何数以百计的文本。在这种情况下,我们又回到一个裸体的文字和功能可以免除。

    • 这一点是,试图隐藏本的文字有没有价值。
      .

  5. 它无法被解释为"硬编码",这是完全不同的东西。我认为那是你的问题是,确定这些结构作为"硬编码".这只是引用Meaningfull PK从字面上。

  6. 现在从这个角度的任何代码段只,如果使用的同样价值几次,你可以改进的编码的字符串在一个变量,然后使用的变量的其余部分的码块。当然不是一个功能。但是,这是一个效率和良好做法的问题。即使这不会改变的影响 IF CountryCode = @cc_aus

以我的经验,这种问题掩盖了更深层次的问题:不实际面向对象的并按照干原则。

概括地说,捕获的决定,在启动时由一个适当的定义,为每个行动 内部if 发言,然后扔掉两个 config_options 和运行测试。

下面详细说明。

样品的使用是:

if (config_options.value('FOO_ENABLED') == 'Y') ...

这引起了明显的问题,"这是怎么回事中的省略号?", 尤其是考虑到以下声明:

(当然,这同样的选择可能需要检查,在许多地方系统中的代码。)

让我们假设,每个这些 config_option 值,确实对应的单个问题领域(或者执行战略)的概念。

而不是做这个(多次,在整个代码):

  1. 拿一串(tag),
  2. 找到其相对应的其他string(值),
  3. 测试,价值为布尔-等同,
  4. 基于这一考验,决定是否执行一些行动。

我建议封的概念"可配置的行动"。

让我们作为一个例子(显然只是作为个hypthetical作 FOO_ENABLED ...;-)就你的代码,有工作的英文单位或量度单位。如果 METRIC_ENABLED 是"真正的"转换用户输入的数据指标以英语内部计算并转换回来之前显示的结果。

定义的接口:

public interface MetricConverter {
    double toInches(double length);
    double toCentimeters(double length);
    double toPounds(double weight);
    double toKilograms(double weight);
}

它识别在一个地方的所有行为相关联的概念 METRIC_ENABLED.

然后写入具体实现所有方式的那些行为是可以进行:

public class NullConv implements MetricConverter {
    double toInches(double length) {return length;}
    double toCentimeters(double length) {return length;}
    double toPounds(double weight)  {return weight;}
    double toKilograms(double weight)  {return weight;}
}

// lame implementation, just for illustration!!!!
public class MetricConv implements MetricConverter {
    public static final double LBS_PER_KG = 2.2D;
    public static final double CM_PER_IN = 2.54D
    double toInches(double length) {return length * CM_PER_IN;}
    double toCentimeters(double length) {return length / CM_PER_IN;}
    double toPounds(double weight)  {return weight * LBS_PER_KG;}
    double toKilograms(double weight)  {return weight / LBS_PER_KG;}
}

在启动时,而非载入一堆 config_options 值,初始化组可配置的行动,如:

MetricConverter converter = (metricOption()) ? new MetricConv() : new NullConv();

(其中表达 metricOption() 上述是在何一时间只有检查你需要做,包括在价值的METRIC_ENABLED;-)

然后,无论在何处的代码一定会说:

double length = getLengthFromGui();
if (config_options.value('METRIC_ENABLED') == 'Y') {
    length = length / 2.54D;
}
// do some computation to produce result
// ...
if (config_options.value('METRIC_ENABLED') == 'Y') {
    result = result * 2.54D;
}
displayResultingLengthOnGui(result);

它改写为:

double length = converter.toInches(getLengthFromGui());
// do some computation to produce result
// ...
displayResultingLengthOnGui(converter.toCentimeters(result));

因为所有的执行情况的详细信息相关的一个概念现在包装干净,今后所有的维护有关 METRIC_ENABLED 可以在一个地方。此外,运行时间贸易是一个赢;在"管理"调用的方法相比微不足道的开销取一串的价值从一个地图和进行串#平等的。

我认为原因有两个,你已经提到,可能的错误拼写,在弦上,不能检测到运行时间和可能性(尽管苗条)的一名称的改变将证明你的想法。

最重要的是,你可以得到输入功能,现在看来你唯一的商店布尔,如果你需要保存一个int,一串等。我宁可使用get_foo()有一种类型,比get_string("FOO")或get_int("FOO").

我真的应该使用常数,并没有硬性编码文本。

你可以说他们不会被改变了,但你可能永远不会知道。这是最好的让它成为习惯。用象征性的常数。

我认为有两个不同的问题:

  • 在目前的项目,该《公约》的使用编码的字符串已经确立,因此,所有开发人员在项目上的工作都很熟悉。它可能是一次最佳的公约》的所有原因,已经列出,但是大家都熟悉的代码可以看看它和本能知道什么代码应该做的事。改变编码,以便在某些部分,它使用的"新的"功能将使代码略更加难以读取(因为人们将不得不考虑,还记得什么新的公约不会)和因此有点难以维持。但我猜想这改变了整个项目新的公约将可能是昂贵的,除非你可以迅速脚本的转换。
  • 新的 的项目,象征性的常数是海事组织,对所有列出的原因. 尤其是 因为任何使编译器抓错误,在编制时间,否则将陷入由一个人在运行时间是一个非常有用的《公约》建立的。

我太喜欢一个强类型配置类,如果它是用来通过出的代码。正确命名方法你就不会失去任何可读性。如果你需要做的从字符串转换为另一种数据类型(小/浮/int),你不需要重复代码转换在多个场所,并可以缓的结果,所以转换,只发生一次。你已经有了基础,这已经使我不认为它将采取得到使用的 新的 的方式做事。

另一个要考虑的一点是,意图。如果你是在一个项目需要的本地化硬编码的字符串可能不明确。考虑以下几点:

const string HELLO_WORLD = "Hello world!";
print(HELLO_WORLD);

程序员的意图是明确的。使用恒定意味着这串不需要进行本地化。现在看看这个示例:

print("Hello world!");

在这里我们不会那么肯定。有没有程序编真的不想要这一串是局部的还是程序员忘记本地化,同时他正在写这个代码?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top