Java Enum Yöntemleri - ters yön numaralandırmasını döndür


113

Ters yönü döndüren bir yöntemi olan bir enum Yönü bildirmek istiyorum (aşağıdaki sözdizimsel olarak doğru değildir, yani numaralandırmalar somutlaştırılamaz, ancak benim açımdan bahsediyor). Bu Java'da mümkün mü?

İşte kod:

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

Sadece bir anahtar kullanın. Sadece 4 vakanız var.
Sotirios Delimanolis

12
Bu arada, d.getCode() * -1==-d.getCode()
tckmn

Bloch's Effective Java'nın 6. Bölümü (en azından 2E'de) ilgi çekici olabilir ve şiddetle tavsiye edilir.
jedwards

ntu.edu.sg/home/ehchua/programming/java/javaenum.html , bölüm 2.1 konsepti düzgün bir şekilde açıkladı
vikramvi

Yanıtlar:


207

Burada başlığa göre cezbedilenler için: evet, numaranızda kendi yöntemlerinizi tanımlayabilirsiniz. Bu tür statik olmayan yöntemi nasıl çağıracağınızı merak ediyorsanız, bunu diğer statik olmayan yöntemlerle aynı şekilde yaparsınız - bu yöntemi tanımlayan veya miras alan tip örneğinde çağırırsınız. Numaralandırma durumunda, bu tür örnekler basitçe ENUM_CONSTANTs'dir.

Yani tek ihtiyacınız olan şey EnumType.ENUM_CONSTANT.methodName(arguments).


Şimdi sorudan soruna geri dönelim. Çözümlerden biri olabilir

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

}

Şimdi Direction.NORTH.getOppositeDirection()dönecek Direction.SOUTH.


Burada @jedwards yorumunu göstermenin biraz daha "hacky" yolu var, ancak daha fazla alan eklemek veya bunların sırasını değiştirmek kodumuzu bozacağından ilk yaklaşım kadar esnek gelmiyor.

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

3
Bir .values()[ordinal()]
hack'lemek üzereydim

nasıl kullanıyorsun peki? ve bu tekniğe ne denir?
Thufir

1
@Thufir " bunu nasıl kullanıyorsunuz " yöntemi hakkında soru soruyorsanız, diğer yöntemler gibi - bu yöntemle onu sınıf örneğinde çağırırsınız . Örneklerini Directionenum sınıfında olan NORTH, EAST, SOUTH, WESTsadece kullanabilmesi NORTH.getOppositeDirection()ve dönecektir SOUTH. " Bu tekniğin adı nedir? " diye soruyorsanız , o static{...}zaman bu statik başlatma bloğudur , sınıf ilk kez yüklendiğinde kod çağrılır (statik alanları başlatan aynı işlemin bir parçasıdır).
Pshemo

@Pshemo, statik blokta ayarlanan değerlerin say properties dosyasından enjekte edilmesi gerekiyorsa yukarıdaki kodun Spring versiyonunun nasıl olacağını merak ediyorum.
Vikas Prasad

161

Bunun gibi küçük bir enum için en okunabilir çözümü şu şekilde buluyorum:

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

}

8
İyi fikir! Bu, genellikle her bir enum değerinin belirli bir davranışa sahip olmasını istediğinizde de iyidir.
OferBr

28

Bu çalışıyor:

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

8
Null döndürmek yerine, uygun bir RuntimeException oluşturan varsayılan bir yan tümce, yeni eklenen bir yön için tersi tanımlamada bir programcı hatası olduğunu belirtmek için daha iyi olabilir.
Timothy055

1
Bu, arayanın boş değeri işlemesini gerektirir. Ayrıca, geliştiricinin her yeni Yön türü eklendiğinde bir servis talebi eklediğinden emin olmasını gerektirir. Amir Afghani'nin her bir enum değeri tarafından geçersiz kılınabilen soyut bir yöntem kullanma konusundaki yanıtına bakın, böylece hiçbir zaman birini kaçırma riskini almazsınız ve boşluğu ele alma konusunda endişelenmenize gerek kalmaz.
Michael Peterson

14

Soyut bir yöntem oluşturun ve numaralandırma değerlerinin her birinin onu geçersiz kılmasını sağlayın. Onu yaratırken bunun tersini bildiğiniz için, onu dinamik olarak oluşturmanıza veya yaratmanıza gerek yoktur.

Yine de iyi okumuyor; belki bir switchdaha yönetilebilir mi?

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

4

Evet bunu her zaman yapıyoruz. Yeni bir Nesne yerine statik bir örnek döndürürsünüz

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

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

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

Numaralandırmalar, enum değerlerinin tümünü bildirildikleri sırayla içeren bir dizi döndüren statik değerler yöntemine sahiptir. kaynak

KUZEY 1, DOĞU 2, GÜNEY 3, BAT 4; tersini elde etmek için basit bir denklem oluşturabilirsiniz:

(değer + 2)% 4


2
neden bu cevap? Bunun gelecekteki okuyucuların veya bu konuda herhangi birinin açıklama yapmadan öğrenmesine nasıl yardımcı olmasını bekliyorsunuz?
GrumpyCrouton

Bu kod soruyu yanıtlayabilirken, sorunun nasıl ve / veya neden çözüldüğüne ilişkin ek içerik sağlamak , yanıtın uzun vadeli değerini artıracaktır. Sadece şimdi soran kişi değil, gelecekte okuyucular için soruyu cevapladığınızı unutmayın! Lütfen bir açıklama eklemek için cevabınızı düzenleyin ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge verin. Ayrıca bu cevabın neden diğerlerinden daha uygun olduğunu belirtmekten de zarar gelmez.
ItamarG3

yorumsuz kod okumak zor mu? yoksa 7 satır kod için özel bir javadoc'a mı ihtiyacınız var?
Pregunton

1
Bu çözüm, enum değerlerinin sıralamasına bağlı olduğundan kırılgandır. Sırayı alfabetik olacak şekilde değiştirirseniz, akıllı denkleminiz artık bunun tam tersini sağlamaz.
Josh J
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.