Java:包含内部枚举的接口;在实现类中扩展功能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3242145/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 17:41:45  来源:igfitidea点击:

Java: Interfaces containing inner enums; Extending functionality in implementation classes

javainterfaceenums

提问by MatthewD

I have an interface like the following:

我有一个如下所示的界面:

package example;
import java.awt.Point;

public interface Thing {
    public enum MovingState {
        MOVING_LEFT,
        MOVING_UP,
        MOVING_RIGHT,
        MOVING_DOWN
    }

    public void setNewPosition(MovingState state);
    public Point getPosition();
}

and an implementation class:

和一个实现类:

package example;
import java.awt.Point;

public class ThingImpl implements Thing {
    public enum MovingState {
        MOVING_LEFT (-1, 0),
        MOVING_UP (0, -1),
        MOVING_RIGHT (1, 0),
        MOVING_DOWN (0, 1);

        private int x_move;
        private int y_move;

        MovingState(int x, int y) {
            x_move = x;
            y_move = y;
        }

        public int xMove() {
            return x_move;
        }

        public int yMove() {
            return y_move;
        }
    }


    private Point position;

    public void setNewPosition(MovingState state) {
        position.translate(state.xMove(), state.yMove());
    }

    public Point getPosition() {
        return position;
    }
}

The idea is to have MovingStatein ThingImplextend MovingStatefrom the Thinginterface (thus separating the actual implementation of MovingStatefrom the interface).

我们的想法是具有MovingStateThingImpl延伸MovingStateThing接口(从而分离所述实际实施方式的MovingState从接口)。

This doesn't work though - the MovingStateenum in ThingImplshadows the definition in the interface instead of extending it, then the compiler complains that ThingImpl is not abstract and does not override abstract method setNewPosition(Thing.MovingState) in Thing.

但这不起作用 - 中的MovingState枚举隐藏ThingImpl了接口中的定义而不是扩展它,然后编译器抱怨ThingImpl 不是抽象的并且没有覆盖 Thing 中的抽象方法 setNewPosition(Thing.MovingState)。

Is there an actual way to do what I'm trying to achieve? Or does Java simply not have this capability?

有没有实际的方法来做我想要实现的目标?或者Java根本就没有这种能力?

采纳答案by MetroidFan2002

What you really want to do is remove the enum declaration from your "ThingImpl" class and move all of it (including its constructor and getters) into the Thing interface.

您真正想要做的是从“ThingImpl”类中删除枚举声明,并将其全部(包括其构造函数和 getter)移动到 Thing 接口中。

Make your fields final in the enum to remember that they shouldn't be touched.

使您的字段在枚举中成为 final,以记住它们不应该被触及。

In this fashion, anything wishing to use the Thing interface must use the enumeration defined on your interface - your problem is that you're effectively defining it twice, but it should either be on the interface (which is fine if it will only be used for this interface) or as a public level enum Java file (using public enum instead of public class). You'd make it a public enum if something other than your interface could reasonably expect to use it - Map.Entry, in my opinion, is a bad nested interface because other classes have use for a key/value pair external to a map and thus it should be its own interface, but we have to live with it :(

以这种方式,任何想要使用 Thing 接口的东西都必须使用接口上定义的枚举 - 你的问题是你有效地定义了它两次,但它应该在接口上(如果它只会被使用,这很好对于此接口)或作为公共级别的枚举 Java 文件(使用公共枚举而不是公共类)。如果您的接口以外的其他东西可以合理地期望使用它,您会将其设为公共枚举 - 在我看来,Map.Entry 是一个糟糕的嵌套接口,因为其他类已用于映射外部的键/值对,并且因此它应该是它自己的接口,但我们必须忍受它:(

The idea is to have MovingState in ThingImpl extend MovingState from the Thing interface (thus separating the actual implementation of MovingState from the interface).

这个想法是让 ThingImpl 中的 MovingState 从 Thing 接口扩展MovingState(从而将MovingState 的实际实现与接口分开)。

I don't think this is really your idea - I think the behavior you've specified on the interface of Thing is fine, you really don't want to touch the MovingState enum as it's fine as it is. If you think something needs a different implementation of MovingState, however, you can make it implement an interface called MovingState and thus you could rename your enum DefaultMovingState. It's your choice.

我不认为这真的是你的想法 - 我认为你在 Thing 的界面上指定的行为很好,你真的不想触摸 MovingState 枚举,因为它很好。但是,如果您认为某些东西需要不同的移动状态实现,您可以使其实现一个名为移动状态的接口,因此您可以重命名您的枚举 DefaultMovingState。这是你的选择。

Your MovingState interface would simply have the getters you're exposing in MovingState right now. Two methods.

您的MovingState 接口将仅具有您现在在MovingState 中公开的getter。两种方法。

回答by hvgotcodes

What you are attempting is an antipattern. Constants should not be defined in an interface.

您正在尝试的是一种反模式。不应在接口中定义常量。

http://en.wikipedia.org/wiki/Constant_interface

http://en.wikipedia.org/wiki/Constant_interface

I would move the constants out of your interface, or simply make them methods, and let your implementations define them by implementing those methods...

我会把常量移出你的接口,或者只是让它们成为方法,让你的实现通过实现这些方法来定义它们......

回答by polygenelubricants

You can't extend an enumbecause it's final.

你不能扩展 anenum因为它是final.

You may want to read Effective Java 2nd Edition, Item 34: Emulate extensible enums with interfaces. Essentially this boils down to the enumitself that implements Something.

您可能需要阅读Effective Java 2nd Edition,Item 34: Emulate extensible enums with interfaces。本质上,这归结为enum本身implements Something

回答by Vivin Paliath

polygenelubricants has given you your answer. I'd like to add something to it, because it was an issue that I ran into.

polygenelubricants 给了你答案。我想添加一些东西,因为这是我遇到的一个问题。

Let's say you have a interface that has many implementations. One method in the interface takes in an enumas an argument. Ideally you would like to have specific sets of enumerated values per implementation. However, since you can't extend enums you can't create a "base" enum and extend from that. The naive approach would be to have a "god" enum that maintains the complete set of enumerated values. But there is a better way. You can use what is known as a marker interface. Effective Java 2nd Ed. talks about this as well. A marker interfacewill not contain any method declarations, but simply marksa class as being a certain type.

假设您有一个具有许多实现的接口。接口中的一种方法将 anenum作为参数。理想情况下,您希望每个实现都有特定的枚举值集。但是,由于您无法扩展枚举,因此无法创建“基本”枚举并从中扩展。天真的方法是拥有一个“上帝”枚举来维护完整的枚举值集。但是有更好的方法。您可以使用所谓的标记界面。有效的 Java 第 2 版。也谈到了这一点。甲标记接口将不包含任何方法声明,而是简单地标记一类为特定类型。

So you can define a marker interface and have all your enums implement that interface. This ties into making the enumextensible, because if you define an interface that your enums extend, you've automatically marked your enums as being a certain type.

因此,您可以定义一个标记接口并让您的所有枚举实现该接口。这与使enum可扩展性有关,因为如果您定义了一个enums 扩展的接口,则您已自动将enums标记为某种类型。

This way you can keep all the specific enumerated values along with their specific implementations (separation of concern).

通过这种方式,您可以保留所有特定枚举值及其特定实现(关注点分离)。

For your case you can do something like this:

对于您的情况,您可以执行以下操作:

public interface MovingInterface {    
   int xMove();
   int yMove();
}

and then:

进而:

public enum MovingState implements MovingInterface {
    MOVING_LEFT (-1, 0),
    MOVING_UP (0, -1),
    MOVING_RIGHT (1, 0),
    MOVING_DOWN (0, 1);

    private int x_move;
    private int y_move;

    MovingState(int x, int y) {
        x_move = x;
        y_move = y;
    }

    public int xMove() {
        return x_move;
    }

    public int yMove() {
        return y_move;
    }
}