Java-Aufzählungsmethoden - Rückgabe der Aufzählung in entgegengesetzter Richtung

113

Ich möchte eine Aufzählungsrichtung deklarieren, die eine Methode hat, die die entgegengesetzte Richtung zurückgibt (das Folgende ist syntaktisch nicht korrekt, dh Aufzählungen können nicht instanziiert werden, aber es veranschaulicht meinen Punkt). Ist das in Java möglich?

Hier ist der Code:

public enum Direction {

     NORTH(1),
     SOUTH(-1),
     EAST(-2),
     WEST(2);

     Direction(int code){
          this.code=code;
     }
     protected int code;
     public int getCode() {
           return this.code;
     }
     static Direction getOppositeDirection(Direction d){
           return new Direction(d.getCode() * -1);
     }
}
Skyler
quelle
Verwenden Sie einfach einen Schalter. Sie haben nur 4 Fälle.
Sotirios Delimanolis
12
Übrigens d.getCode() * -1==-d.getCode()
tckmn
Kapitel 6 (zumindest in 2E) von Blochs effektivem Java könnte von Interesse sein und wird dringend empfohlen.
jedwards
ntu.edu.sg/home/ehchua/programming/java/javaenum.html , Abschnitt 2.1 hat das Konzept ordentlich erklärt
vikramvi

Antworten:

205

Für diejenigen, die hier nach Titel gelockt werden: Ja, Sie können Ihre eigenen Methoden in Ihrer Aufzählung definieren. Wenn Sie sich fragen, wie Sie eine solche nicht statische Methode aufrufen sollen, gehen Sie genauso vor wie bei jeder anderen nicht statischen Methode - Sie rufen sie bei einer Instanz des Typs auf, der diese Methode definiert oder erbt. Bei Aufzählungen sind solche Instanzen einfach ENUM_CONSTANTs.

Alles was Sie brauchen ist EnumType.ENUM_CONSTANT.methodName(arguments).


Kehren wir nun von Frage zu Problem zurück. Eine der Lösungen könnte sein

public enum Direction {

    NORTH, SOUTH, EAST, WEST;

    private Direction opposite;

    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        EAST.opposite = WEST;
        WEST.opposite = EAST;
    }

    public Direction getOppositeDirection() {
        return opposite;
    }

}

Jetzt Direction.NORTH.getOppositeDirection()wird zurückkehren Direction.SOUTH.


Hier ist etwas "hackiger", um @ jedwards Kommentar zu veranschaulichen , aber es fühlt sich nicht so flexibel an wie der erste Ansatz, da das Hinzufügen weiterer Felder oder das Ändern ihrer Reihenfolge unseren Code beschädigen wird.

public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    // cached values to avoid recreating such array each time method is called
    private static final Direction[] VALUES = values();

    public Direction getOppositeDirection() {
        return VALUES[(ordinal() + 2) % 4]; 
    }
}
Pshemo
quelle
3
Ich wollte gerade einen .values()[ordinal()]Hack
auslösen,
wie benutzt du es aber? und wie heißt diese Technik?
Thufir
1
@Thufir " Wie verwenden Sie es ?" Wenn Sie nach einer Methode fragen, rufen Sie sie wie jede andere Methode bei einer Klasseninstanz mit dieser Methode auf. Instanzen von DirectionEnum - Klasse sind NORTH, EAST, SOUTH, WESTso dass Sie nur verwenden können , NORTH.getOppositeDirection()und es wird zurückkehren SOUTH. " Wie heißt diese Technik? " Wenn Sie nachfragen, handelt static{...}es sich um einen statischen Initialisierungsblock . Es handelt sich um Code, der beim ersten Laden der Klasse aufgerufen wird (er ist Teil desselben Prozesses, der statische Felder initialisiert).
Pshemo
@Pshemo, ich frage mich, wie die Spring-Version des obigen Codes aussehen wird, wenn die Werte, die im statischen Block festgelegt werden, aus der Eigenschaftendatei eingefügt werden müssen.
Vikas Prasad
162

Für eine kleine Aufzählung wie diese finde ich die am besten lesbare Lösung:

public enum Direction {

    NORTH {
        @Override
        public Direction getOppositeDirection() {
            return SOUTH;
        }
    }, 
    SOUTH {
        @Override
        public Direction getOppositeDirection() {
            return NORTH;
        }
    },
    EAST {
        @Override
        public Direction getOppositeDirection() {
            return WEST;
        }
    },
    WEST {
        @Override
        public Direction getOppositeDirection() {
            return EAST;
        }
    };


    public abstract Direction getOppositeDirection();

}
Amir Afghani
quelle
8
Großartige Idee! Dies ist auch gut, wenn Sie im Allgemeinen möchten, dass jeder Aufzählungswert ein bestimmtes Verhalten aufweist.
OferBr
28

Das funktioniert:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction oppose() {
        switch(this) {
            case NORTH: return SOUTH;
            case SOUTH: return NORTH;
            case EAST:  return WEST;
            case WEST:  return EAST;
        }
        throw new RuntimeException("Case not implemented");
    }
}
Pikrass
quelle
8
Anstatt null zurückzugeben, ist eine Standardklausel, die eine geeignete RuntimeException auslöst, möglicherweise besser, um anzuzeigen, dass ein Programmiererfehler aufgetreten ist, wenn für eine neu hinzugefügte Richtung kein Gegenteil definiert wurde.
Timothy055
1
Dies erfordert, dass der Aufrufer null behandelt. Außerdem muss der Betreuer sicherstellen, dass jedes Mal, wenn ein neuer Richtungstyp hinzugefügt wird, ein Fall hinzugefügt wird. Lesen Sie die Antwort von Amir Afghani über die Verwendung einer abstrakten Methode, die von jedem Enum-Wert überschrieben werden kann. Auf diese Weise riskieren Sie nie, einen zu verpassen, und Sie müssen sich keine Gedanken über den Umgang mit Null machen.
Michael Peterson
14

Erstellen Sie eine abstrakte Methode und lassen Sie sie von jedem Ihrer Aufzählungswerte überschreiben. Da Sie beim Erstellen das Gegenteil kennen, müssen Sie es nicht dynamisch generieren oder erstellen.

Es liest sich aber nicht gut; vielleicht switchwäre ein überschaubarer?

public enum Direction {
    NORTH(1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.SOUTH;
        }
    },
    SOUTH(-1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.NORTH;
        }
    },
    EAST(-2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.WEST;
        }
    },
    WEST(2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.EAST;
        }
    };

    Direction(int code){
        this.code=code;
    }
    protected int code;

    public int getCode() {
        return this.code;
    }

    public abstract Direction getOppositeDirection();
}
Makoto
quelle
4

Ja, wir machen es die ganze Zeit. Sie geben eine statische Instanz anstelle eines neuen Objekts zurück

 static Direction getOppositeDirection(Direction d){
       Direction result = null;
       if (d != null){
           int newCode = -d.getCode();
           for (Direction direction : Direction.values()){
               if (d.getCode() == newCode){
                   result = direction;
               }
           }
       }
       return result;
 }
BevynQ
quelle
0
public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    public Direction getOppositeDirection(){
        return Direction.values()[(this.ordinal() + 2) % 4];
    }
}

Aufzählungen haben eine statische Wertemethode, die ein Array zurückgibt, das alle Werte der Aufzählung in der Reihenfolge enthält, in der sie deklariert sind. Quelle

da NORTH 1 bekommt, bekommt EAST 2, SOUTH 3, WEST 4; Sie können eine einfache Gleichung erstellen, um die entgegengesetzte zu erhalten:

(Wert + 2)% 4

Pregunton
quelle
2
Warum ist das die Antwort? Wie erwarten Sie, dass dies zukünftigen Lesern oder anderen Personen hilft, ohne Erklärung zu lernen?
GrumpyCrouton
Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt! Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, und geben Sie an, welche Einschränkungen und Annahmen gelten. Es tut auch nicht weh zu erwähnen, warum diese Antwort angemessener ist als andere.
ItamarG3
Ist es schwierig, Code ohne Kommentare zu lesen? oder benötigen Sie ein Javadoc exklusiv für 7 Codezeilen?
Pregunton
1
Diese Lösung ist spröde, da sie von der Reihenfolge der Enum-Werte abhängt. Wenn Sie die Reihenfolge so ändern würden, dass sie alphabetisch ist, würde Ihre clevere Gleichung nicht mehr das richtige Gegenteil liefern.
Josh J