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

发布于 2024-09-09 04:35:17 字数 1470 浏览 2 评论 0原文

我有一个如下所示的接口:

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

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

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

有没有实际的方法可以实现我想要实现的目标?或者Java根本不具备这种能力?

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 MovingState in ThingImpl extend MovingState from the Thing interface (thus separating the actual implementation of MovingState from the interface).

This doesn't work though - the MovingState enum in ThingImpl shadows 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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

原来是傀儡 2024-09-16 04:35:17

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

将您的字段放在枚举中的最后,以记住它们不应该被触及。

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

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

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

您的 MovingState 接口将只包含您现在在 MovingState 中公开的 getter。两种方法。

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.

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

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 :(

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

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.

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

念三年u 2024-09-16 04:35:17

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

您可能想阅读《Effective Java 第二版》,第 34 项:使用接口模拟可扩展枚举。本质上,这可以归结为枚举本身实现了某些东西

You can't extend an enum because it's final.

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

Bonjour°[大白 2024-09-16 04:35:17

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

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

Let's say you have a interface that has many implementations. One method in the interface takes in an enum as 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 interface will not contain any method declarations, but simply marks a class as being a certain type.

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

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;
    }
}
我为君王 2024-09-16 04:35:17

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

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

我会将常量移出您的接口,或者只是将它们设为方法,然后让您的实现通过实现这些方法来定义它们......

What you are attempting is an antipattern. Constants should not be defined in an 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...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文