一个类应该实现一个只有常量的接口吗?

时间:2010-01-14 10:38:32

标签: java

今天我查看了ZipEntry课程并找到了以下内容:

public class ZipEntry implements ZipConstants, Cloneable

ZipConstants没有定义任何方法 - 只有常量(static final int LOCHDR = 30

然后我发现使用常量实现接口可以直接访问这些常量,就好像它们是在类本身中定义的一样。例如:

public interface Constants {
    static final int CONST = 2;
}

public class implements Constants {
    int doSomething(int input) {
        return CONST * input;
    }
}

除了以下之外,还有其他原因不使用它吗?

  • 首先是混淆来自
  • 的常量
  • 使用接口进行常量定义
  • 被认为是错误的

我很好奇,因为这绝对不是一种常见的做法。

6 个答案:

答案 0 :(得分:16)

不使用此的另一个原因:

从Java 5开始,有一个“干净”的语言功能可以实现相同的目标:static imports

实现接口以使用常量基本上是模拟静态导入的Java-5之前的黑客攻击。

答案 1 :(得分:3)

并不是你想象的那么罕见,例如在Parasofts JTest的静态分析中,应该在class中声明常量的规则和在{中声明常量的规则{1}}存在,并且由项目在它们之间进行选择。

那就是说,在我的所有项目中,我都不允许在接口中定义常量。创建有意义的类并明确常量的上下文使得代码比开发人员必须检查一个类中使用的常量实际上与另一个类中的常量相同(或不是)时,使代码更易读并且因此可维护。 )

答案 2 :(得分:3)

我认为使用共享常量的接口是混淆两个不同概念的一个例子:

  1. 代码重用
  2. 分型
  3. 根据我使用子类化或接口实现的经验,只是为了防止代码重复导致问题。你的代码变得更脆弱。例如,有人可能会意外地重新定义常量 - 特别是如果您的类层次结构是多个类的深度。

    通常最好使用合成来保持代码干净。

    以这种方式使用继承的另一个问题是,通常这种类型的继承构成了类的API的一部分。类的层次结构在类之外是可见的。这破坏了封装。您不需要在类之外公开使用常量,它们与您选择实现类的方式有关,而不是其API的一部分(在您的示例中)。

    这可能导致可怕的向后兼容性问题。其他人可能会出现这样的代码:

    public interface Constants {
       static final int CONST = 2;
    }
    
    public class MyClass implements Constants {
       int doSomething(int input) {
        return CONST * input;
       }
    }
    
    public class ThirdPartyClass {
       int doSomethingElse(int input) {
         return MyClass.CONST + input;
       }
    }
    

    现在,如果您决定不再需要在MyClass中使用CONST,那么您将陷入困境。因为ThirdPartyClass已经创建了对可在MyClass中使用的CONST的依赖。

    你最终可以这样做。 MyClass没有使用界面中的任何常量,但仍然需要实现它。

    public interface Constants {
       static final int CONST = 2;
    }
    
    public class MyClass implements Constants {
       int doSomething(int input) {
        return input;
       }
    }
    
    public class ThirdPartyClass {
       int doSomethingElse(int input) {
         return MyClass.CONST + input;
       }
    }
    

    总之;永远不要这样做!

答案 3 :(得分:2)

  

...因为使用接口进行常量定义被认为是错误的

这是不做某事的坏理由。事实上,这根本不是理由。

修改

考虑一下。

  • XXX风格不好的原因是YYY。
  • 你应该做XXX的原因是风格不好。

有多少实质性原因没有做XXX?一个或两个?

如果答案是两个,我可以通过添加额外的微妙原因链来制作三个,四个,五个等等。例如“你不应该做XXX的原因是因为这是一个坏主意。” “它是一个坏主意的原因是它的风格很糟糕”。等等。这显然是愚蠢的。

没有真正的不做XXX的原因是YYY,而“坏样式”的原因不是实质性原因。相反,它是因为YYY和ZZZ以及任何其他实质性原因而说不做XXX的捷径。

事实上,即使OP的“令人困惑”的原因也未完全陈述。为什么令人困惑?

因为接口通常是具有实现接口的类的类型是子类型。但是,常量接口不是任何有用意义上的类型,实现接口的类在任何有用的意义上都不是子类型。最终,这是实现仅限常量接口称为坏样式和“反模式”的真正原因,这是在Java 5中添加静态导入的主要原因。

答案 4 :(得分:0)

不,这也被称为“恒定接口反模式”。另一种方法是编写一个定义常量的具体类,然后使用静态导入。

类常量

package util;

public class Constants {
    public static final String CONSTANT_STRING = "abc";

    private Constants() {
        throw new AssertionError(); 
    }
}

班级考试

import static util.Constants.CONSTANT_STRING;

public class Test {
    System.out.println(CONSTANT_STRING);
}

Wikipedia

了解更多详情。

答案 5 :(得分:0)

不将常量放在界面中的一个原因是,如果将界面暴露给第三方,他们就可以访问常量。 这可能似乎不是一个坏主意,但想象一下,如果你想改变常量的值,但人们仍在使用旧的界面。

当您向界面添加内容时,它有可能被设置为一块石头,因此只添加您希望其他人查看和使用的内容。