Effective-java 3 中文翻译系列 (Item 22 仅仅使用接口来定义类型)

原文链接

文章也上传到

github

(欢迎关注,欢迎大神提点。)


Item 22 仅仅使用接口来定义类型


当一个类实现了一个接口时,这个接口就被当作一个可以引用该类对象的类型在使用。因此类实现了哪个接口,就能调用哪个接口的方法。
用接口类定义其他事情都是不恰当。
有一种失败的接口是常量接口。这样的接口没有包含任何方法,仅仅包含一些static final的常量。这里有个例子:

//常量接口反例-不要这样用
public interface PhysicalConstants {
    // Avogadro's number (1/mol)
    static final double AVOGADROS_NUMBER =
            6.022_140_857e23;
    // Boltzmann constant (J/K)
    static final double BOLTZMANN_CONSTANT =
            1.380_648_52e-23;
    // Mass of the electron (kg)
    static final double ELECTRON_MASS = 9.109_383_56e-31;
}

这个常量接口是对接口的不良用法。类使用的什么常量属于内部的实现细节。但是当类实现一个常量接口时,就会导致类的内部实现细节被暴漏到类导出的API中。对用户来说,类实现常量接口不但用处不大而且容易造成混乱。更糟糕的是,常量接口代表了一个承诺:如果将来类被修改成不再需要使用这些常量,但它为了二进制兼容还必须继续实现这个接口,这很痛苦。如果一个非final的类实现了常量接口,那么它子类的命名空间就可能被这些常量污染。
在JAVA平台库中有几个常量接口存在,例如java.io.ObjectStreamConstants.这些接口应该被视为不规则的不应该被效仿的接口。
如果你想导出常量,有几种合理的选择。

  • 如果常量与现有的类或者接口强关联,那么你应该把他们添加到这个类和接口上。例如,所有的原始数值包装类中,像Integer和Double,都导出了MIN_VALUE和MAX_VALUE常量。
  • 如果常量是被当作枚举使用的,那么你就应该把常量导出成一个enum类型(Item34)。
  • 否则,你应该导出一个不可实例化的工具类包含这些常量(Item4)。例如前面的例子:
    package com.effectivejava.science;
    public class PhysicalConstants {
        private PhysicalConstants() { } // Prevents instantiation
        public static final double AVOGADROS_NUMBER =
                6.022_140_857e23;
        public static final double BOLTZMANN_CONST =
                1.380_648_52e-23;
        public static final double ELECTRON_MASS =
                9.109_383_56e-31;
    }

顺便说一下,注意在上面的数字中使用的下划线(_),从Java7开始是合法的使用,添加下划线不会影响数字的值,而且能使数字的可读性更强。无论是整数还是小数,当数字个数超过5个的时候,你都可以每3个分成一组来划分。

通常使用工具类调用常量时要求用类名.常量名,例如PhysicalConstants.AVOGADROS_NUMBER.但是如果你大量的使用常量时,可以通过导入工具类来直接使用常量:

    import static com.effectivejava.science.PhysicalConstants.*;
    
    public class Test {
        double atoms(double mols) {
            return AVOGADROS_NUMBER * mols;
        }
        ...
        // Many more uses of PhysicalConstants justify static import
    }

总结:接口应该仅被用于定义类型,而不应该用于仅仅导出常量。

你可能感兴趣的:(Effective-java 3 中文翻译系列 (Item 22 仅仅使用接口来定义类型))