当前位置:  开发笔记 > 编程语言 > 正文

硬编码的STRINGS是否可以接受?

如何解决《硬编码的STRINGS是否可以接受?》经验,为你挑选了4个好方法。

类似于硬编码文字是否可以接受?,但我在这里特别想到"魔法字符串".

在一个大型项目中,我们有一个配置选项表,如下所示:

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

(数以百计).

通常的做法是调用泛型函数来测试这样的选项:

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

(当然,可能需要在系统代码的许多地方检查相同的选项.)

添加新选项时,我正在考虑添加一个隐藏"魔术字符串"的函数,如下所示:

if (config_options.foo_enabled()) ...

然而,同事们认为我已经过火了并反对这样做,更喜欢硬编码,因为:

这就是我们通常做的事情

它使得在调试代码时更容易看到发生了什么

麻烦的是,我可以看到他们的观点!实际上,我们永远不会出于任何原因重命名选项,因此我能为我的函数考虑的唯一优势是编译器会捕获像fo_enabled()这样的拼写错误,但不能捕获'FO_ENABLED'.

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



1> Jon Skeet..:

如果我在代码中使用一次字符串,我通常不担心在某处使它成为常量.

如果我在代码中使用两次字符串,我会考虑使它成为常量.

如果我在代码中使用三次字符串,我几乎肯定会使它成为常量.



2> JeeBee..:
if (config_options.isTrue('FOO_ENABLED')) {...
}

将硬编码的Y检查限制在一个地方,即使这意味着为您的地图编写包装类.

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

在您拥有100个配置选项和100个方法之前,可能看起来没问题(因此,您可以在决定实施之前对未来的应用程序增长和需求做出判断).否则,最好为参数名称提供一类静态字符串.

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



3> joel.neely..:

根据我的经验,这类问题掩盖了一个更深层次的问题:未能实际实施OOP并遵循DRY原则.

概括地说,通过对每个动作的适当定义捕捉在启动时决定里面if语句,然后扔掉这两个config_options和运行时间测试.

详情如下.

样本用法是:

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

这提出了一个显而易见的问题,"省略号中发生了什么?",特别是考虑到以下声明:

(当然,可能需要在系统代码的许多地方检查相同的选项.)

让我们假设这些config_option值中的每一个确实对应于单个问题域(或实现策略)概念.

而不是这样做(反复,在整个代码的各个地方):

    拿一个字符串(标签),

    找到相应的其他字符串(值),

    将该值测试为布尔值等效值,

    根据该测试,决定是否执行某些操作.

我建议封装"可配置动作"的概念.

让我们以FOO_ENABLED你的代码必须以英制单位或公制单位工作为例(显然就像...... ;-) 一样谦虚.如果METRIC_ENABLED为"true",则将用户输入的数据从公制转换为英语以进行内部计算,并在显示结果之前进行转换.

定义一个接口:

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都可以在一个地方完成.此外,运行时权衡是一个胜利; 与从Map中获取String值并执行String#equals的开销相比,调用方法的"开销"是微不足道的.



4> PerformanceD..:

我意识到这个问题已经过时了,但是我的问题就出现了.

AFAIC,这个问题尚未在问题或答案中准确确定.暂时忘掉"扼杀字符串"吧.

    该数据库有一个Reference表,包含config_options.PK是一个字符串.

    PK有两种类型:

    用户(和开发人员)查看和使用的有意义的标识符.这些PK应该是稳定的,可以依赖它们.

    Id用户不应该看到的无意义的列,开发人员必须知道的,并且编码.这些都不能依赖.

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

    引用无意义PK的绝对值是不可接受的(由于自动增加;间隙被改变;值被批量替换).
    .

    您的参考表使用有意义的PK.在代码中引用这些文字字符串是不可避免的.隐藏价值将使维护更加困难; 代码不再是字面意思; 你的同事是对的.另外还有额外的冗余功能可以咀嚼循环.如果字面上有拼写错误,很快就会在开发测试期间找到它,早在UAT之前.

    数百个文字的数百个函数是荒谬的.如果你实现了一个函数,那么规范化你的代码,并提供一个可以用于数百个文字中的任何一个的函数.在这种情况下,我们回到裸体文字,并且可以省去该功能.

    关键是,隐藏文字的尝试没有任何价值.
    .

    它不能被解释为"硬编码",这是完全不同的东西.我认为这就是你的问题所在,将这些结构标识为"硬编码".它只是字面上引用了一个有意义的PK.

    现在仅从任何代码段的角度来看,如果您使用相同的值几次,则可以通过捕获变量中的文字字符串来改进代码,然后在代码块的其余部分中使用该变量.当然不是一个功能.但这是一个效率和良好实践问题.即使这样也不会改变效果IF CountryCode = @cc_aus

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有