java 常量接口反模式澄清
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29382728/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Constant Interface Anti-Pattern Clarification
提问by Grateful
I just read somewhere that having an interface with common project constants is bad practice and also known as the Constant Interface Anti-Pattern. If I understood this correctly, the reason provided was that once implemented, the class would expose these constants to the public.
我刚刚在某处读到具有通用项目常量的接口是不好的做法,也称为Constant Interface Anti-Pattern。如果我理解正确的话,提供的原因是一旦实现,该类就会向公众公开这些常量。
Well, I don't understand the need for 'implementing' in the first place. Isn't it possible to just use these static constants directly? So why do I have to go through the trouble of import static
when I can do something like:
好吧,我首先不明白“实施”的必要性。是不是可以直接使用这些静态常量?那么为什么我必须经历这样的麻烦:import static
什么时候我可以做这样的事情:
interface Constants {
public static final int FOO_1 = 1;
public static final int FOO_2 = 2;
}
public class Test {
public static void main(String[] args) {
System.out.println(Constants.FOO_2);
}
}
I would appreciate any guidance to help me understand this a bit more.
我将不胜感激任何帮助我理解这一点的指导。
采纳答案by Grateful
I realised... the fact that the interface CAN be implemented by an individual if desired, leaves room for the issues pointed out above (i.e. namespace pollution, non-conventional use, exposure through public API ). So it's best to prevent the ability to implement the interface altogether. Hence, it's more appropriate to have a final
class with a private constructor so that it can't be instantiated / extended.
我意识到......如果需要,接口可以由个人实现,这一事实为上面指出的问题留下了空间(即命名空间污染、非常规使用、通过公共 API 暴露)。所以最好完全阻止实现接口的能力。因此,拥有一个final
带有私有构造函数的类更合适,这样它就不能被实例化/扩展。
public final class Constants
{
// to restrict instantiation
private Constants() {}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
... and use that in combination with the import static
.
... 并将其与import static
.
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations
{
public double getReducedPlanckConstant()
{
return PLANCK_CONSTANT / ( 2 * PI );
}
}
回答by scottb
The arguments against the "Constant Interface Pattern" are mainly stylistic. You canuse a Constant Interface in Java if it suits your need and in fact the Java libraries include a few of these (though they are considered poor examples that shouldn't be repeated).
反对“常量接口模式”的论据主要是风格上的。如果它适合您的需要,您可以在 Java 中使用常量接口,实际上 Java 库包括其中的一些(尽管它们被认为是不应该重复的糟糕示例)。
The reasons why the Constant Interface is considered by many to be an "anti-pattern" are enumerated in Effective Java, 2nd Ed. Briefly, some of the reasons that this use of interfaces are discouraged include:
许多人认为常量接口是“反模式”的原因在 Effective Java,第 2 版中列举。简而言之,不鼓励使用接口的一些原因包括:
Namespace pollution. The named constants appear in the namespace of all implementing classes as well as their subclasses.
Interfaces should define types. In Java, most of the major types in a project should be represented by interfaces. A constant interface by its nature does not define a type.
Noninstantiable classes with
import static
. Declaring constants as static final fields in a class (rather than an interface) achieves all the same objectives as declaring them in an interface. Doing so does not create namespace pollution by the class. If desired, these constants can be used without the qualifying class name by using theimport static
declaration.Interfaces should specify behavior. An interface is supposed to define a contract between the interface and implementing classes. Implementing the interface is supposed to say something about what the class can do. Constant interfaces do not follow this pattern.
命名空间污染。命名常量出现在所有实现类及其子类的命名空间中。
接口应该定义类型。在 Java 中,项目中的大多数主要类型都应该由接口表示。本质上,常量接口不定义类型。
不可实例化的类
import static
。在类(而不是接口)中将常量声明为静态 final 字段与在接口中声明它们实现了所有相同的目标。这样做不会造成类的命名空间污染。如果需要,可以通过使用import static
声明在没有限定类名的情况下使用这些常量。接口应该指定行为。接口应该定义接口和实现类之间的契约。实现接口应该说明类可以做什么。常量接口不遵循这种模式。
回答by Bohemian
That's not quite the pattern. It's more like:
那不完全是模式。它更像是:
interface Constants {
final int FOO_1 = 1;
final int FOO_2 = 2;
}
public class MyClass implements Constants {
public static void main( String[] args ) {
System.out.println( FOO_2 ); // compiles OK
}
}
IMHO, the issue is that MyClass
"is not a" Constants
. The pattern uses a trick of visibility, but clouds the intention of the class. Further, field shadowingcan occur without compiler warnings - this is all the more likely because you see allthe fields of the interface, even if you don't use them all.
恕我直言,问题是MyClass
“不是” Constants
。该模式使用了可见性技巧,但掩盖了类的意图。此外,可能会在没有编译器警告的情况下发生字段遮蔽——这种情况更有可能发生,因为您会看到接口的所有字段,即使您没有全部使用它们。
It's better to import static com.foo.Constants.*;
to achieve the same coding convenience, without the misdirection of being a member of Constants
.
最好能import static com.foo.Constants.*;
达到同样的编码便利性,又不会被误入歧途Constants
。
回答by Rishabh Agarwal
We can use both class(finalwith private constructor) and Interface.
我们可以同时使用类(带有私有构造函数的final)和接口。
However I would prefer class due to the following reasons:
但是,由于以下原因,我更喜欢上课:
Interface and its implementing classes should have a IS Arelationship. Eg: "Cat extends Mammal" means Cat is a Mammal. This doesn't hold true in case we implement constants we use in interfaces.
Interface should define a type.
However now, we can use static importwith Interface as well but there is a risk with someone implementing it which will violate "IS A" relationship.
接口和它的实现类应该有一个IS A关系。例如:“猫延伸哺乳动物”意味着猫是哺乳动物。如果我们实现了我们在接口中使用的常量,这就不成立了。
接口应该定义一个类型。
但是现在,我们也可以对接口使用静态导入,但是有人实施它存在风险,这会违反“IS A”关系。
Have a class (with following properties) for constants and make it:
为常量创建一个类(具有以下属性)并创建它:
- FINAL- so it cannot be inheritedby other classes.
- Having only a private Constructor:- so it cannot be instantiated.
- FINAL- 所以它不能被其他类继承。
- 只有一个私有构造函数:-所以它不能被实例化。
PS: copying the used example
PS:复制使用过的例子
public final class Constants // so it cannot be inherited
{
private Constants() {} // to restrict instantiation
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
Now the usage:
现在的用法:
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations
{
public double getReducedPlanckConstant()
{
return PLANCK_CONSTANT / ( 2 * PI );
}
}