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

时间:2010-07-13 22:44:51

标签: java interface enums

我有如下界面:

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();
}

和实现类:

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;
    }
}

我们的想法是让MovingState ThingImplMovingState接口扩展Thing(从而将MovingState的实际实现与接口分开)。

这不起作用 - MovingState ThingImpl enum在界面中影响定义而不是扩展它,然后编译器抱怨 ThingImpl不是抽象的并且不会覆盖事物中的抽象方法setNewPosition(Thing.MovingState)。

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

4 个答案:

答案 0 :(得分:11)

您真正想要做的是从“ThingImpl”类中删除枚举声明,并将所有这些声明(包括其构造函数和getter)移动到Thing界面中。

让你的字段在枚举中最后记住,不要碰它们。

以这种方式,任何希望使用Thing接口的东西都必须使用你界面上定义的枚举 - 你的问题是你有效地定义了两次,但是它应该在界面上(如果它会在仅用于此接口)或作为公共级枚举Java文件(使用公共枚举而不是公共类)。如果你的界面之外的其他东西可以合理地期望使用它,你就会把它变成公共枚举 - 在我看来,Map.Entry是一个糟糕的嵌套接口,因为其他类用于地图外部的键/值对因此它应该是它自己的界面,但我们必须忍受它:(

  

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

我认为这不是你的想法 - 我认为你在Thing接口上指定的行为很好,你真的不想触摸MovingState枚举,因为它很好。但是,如果您认为某些内容需要不同的MovingState实现,则可以使其实现名为MovingState的接口,从而可以重命名枚举DefaultMovingState。这是你的选择。

您的MovingState接口将立即拥有您在MovingState中公开的getter。两种方法。

答案 1 :(得分:5)

您无法扩展enum,因为它是final

您可能需要阅读 Effective Java 2nd Edition,第34项:使用接口模拟可扩展枚举。从本质上讲,这归结为enum本身implements Something

答案 2 :(得分:3)

polygenelubricants给了你答案。我想补充一点,因为这是我遇到的一个问题。

假设您有一个具有许多实现的接口。接口中的一个方法接受enum作为参数。理想情况下,您希望每个实现具有特定的枚举值集。但是,由于您无法扩展枚举,因此无法创建“基础”枚举并从中扩展。天真的方法是拥有一个“上帝”枚举,它维护着一整套枚举值。但还有更好的方法。您可以使用所谓的标记接口。有效的Java第二版。也谈到这一点。 标记接口不包含任何方法声明,只是类标记为某种类型。

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

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

对于您的情况,您可以这样做:

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

然后:

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;
    }
}

答案 3 :(得分:-2)

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

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

我会将常量移出你的界面,或者只是简单地创建它们,让你的实现通过实现这些方法来定义它们......