Yanıtlar:
Numaralamalar sadece pasif kümeleri (ör. Renkleri) temsil etmek zorunda değildir. İşlevselliği olan daha karmaşık nesneleri temsil edebilirler ve bu nedenle bunlara daha fazla işlevsellik eklemek isteyeceksiniz - örneğin Printable
, Reportable
vb. Gibi arayüzlere ve bunları destekleyen bileşenlere sahip olabilirsiniz.
İşte bir örnek (Effective Java 2nd Edition'da benzer / daha iyi bir örnek bulunur):
public interface Operator {
int apply (int a, int b);
}
public enum SimpleOperators implements Operator {
PLUS {
int apply(int a, int b) { return a + b; }
},
MINUS {
int apply(int a, int b) { return a - b; }
};
}
public enum ComplexOperators implements Operator {
// can't think of an example right now :-/
}
Şimdi hem Basit + Karmaşık Operatörlerin bir listesini almak için:
List<Operator> operators = new ArrayList<Operator>();
operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));
Yani burada genişletilebilir numaralandırmaları simüle etmek için bir arayüz kullanıyorsunuz (arayüz kullanmadan mümkün olmaz).
Comparable
Birkaç kişi tarafından verilen örnek burada beri yanlış olduğunu Enum
zaten uygular söyledi. Bunu bile geçersiz kılamazsınız.
Daha iyi bir örnek, bir veri türünü tanımlayan bir arayüze sahip olmaktır. Basit türleri uygulamak için bir numaralandırma yapabilir ve karmaşık türleri uygulamak için normal sınıflara sahip olabilirsiniz:
interface DataType {
// methods here
}
enum SimpleDataType implements DataType {
INTEGER, STRING;
// implement methods
}
class IdentifierDataType implements DataType {
// implement interface and maybe add more specific methods
}
Sık kullandığım bir durum var. IdUtil
Çok basit bir Identifiable
arayüz uygulamak nesneleri ile çalışmak için statik yöntemlerle bir sınıf var :
public interface Identifiable<K> {
K getId();
}
public abstract class IdUtil {
public static <T extends Enum<T> & Identifiable<S>, S> T get(Class<T> type, S id) {
for (T t : type.getEnumConstants()) {
if (Util.equals(t.getId(), id)) {
return t;
}
}
return null;
}
public static <T extends Enum<T> & Identifiable<S>, S extends Comparable<? super S>> List<T> getLower(T en) {
List<T> list = new ArrayList<>();
for (T t : en.getDeclaringClass().getEnumConstants()) {
if (t.getId().compareTo(en.getId()) < 0) {
list.add(t);
}
}
return list;
}
}
Bir oluşturursam Identifiable
enum
:
public enum MyEnum implements Identifiable<Integer> {
FIRST(1), SECOND(2);
private int id;
private MyEnum(int id) {
this.id = id;
}
public Integer getId() {
return id;
}
}
O zaman id
bu şekilde alabilirim:
MyEnum e = IdUtil.get(MyEnum.class, 1);
Numaralandırmalar arabirimleri uygulayabildiğinden, tekil kalıbın sıkı bir şekilde uygulanması için kullanılabilirler. Standart bir sınıfı bir singleton yapmaya çalışmak ...
Tek tonlu numaralandırmalar bu güvenlik sorunlarını önlemeye yardımcı olur. Bu, Enums'ın sınıf olarak hareket etmesine ve arabirimleri uygulamasına izin vermenin katkıda bulunan nedenlerinden biri olabilir. Sadece bir tahmin.
Daha fazla tartışma için /programming/427902/java-enum-singleton ve Java'daki Singleton sınıfına bakın .
for inheriting from your singleton and overriding your singleton's methods with something else
. Bunu final class
önlemek için sadece bir kullanabilirsiniz
Genişletilebilirlik için gereklidir - birisi geliştirdiğiniz bir API kullanıyorsa, tanımladığınız numaralandırmalar statiktir; eklenemez veya değiştirilemez. Ancak, bir arabirim uygulamasına izin verirseniz, API kullanan kişi aynı arabirimi kullanarak kendi numaralandırmasını geliştirebilir. Daha sonra bu numaralandırmayı, standart arayüzle birlikte numaralandıran bir numaralandırma yöneticisi ile kaydedebilirsiniz.
Edit: @Helper Yöntemi bunun mükemmel bir örneğine sahiptir. Diğer kütüphanelerin yeni operatörleri tanımlamasını ve ardından bir yönetici sınıfına 'hey, bu numaralandırma var - kaydettir' demesini söyleyin. Aksi takdirde, Operatörleri yalnızca kendi kodunuzla tanımlayabilirsiniz - genişletilebilirlik olmazdı.
Numaralandırmalar sadece kılık değiştirmiş sınıflardır, bu yüzden çoğunlukla, bir enum ile yapabileceğiniz bir sınıfla yapabileceğiniz her şey.
Bir enum'un bir arabirim uygulayamaması için bir neden düşünemiyorum, aynı zamanda onlar için de iyi bir neden düşünemiyorum.
Bir numaralandırmaya arabirimler veya yöntem gibi bir şey eklemeye başladığınızda, bunun yerine bir sınıf yapmayı düşünmelisiniz. Elbette geleneksel olmayan numaralandırma işleri yapmak için geçerli durumlar olduğundan eminim ve sınır yapay bir tane olacağından, insanların orada istediklerini yapmalarına izin vermekten yanayım.
Bunun en yaygın kullanımı, iki enumun değerlerini bir grupta birleştirmek ve onlara benzer şekilde davranmak olacaktır. Örneğin, Meyve ve Sebzelerin nasıl katılacağına bakın .
Enum'ları arayüzle kullanmamın en iyi kullanım durumlarından biri Predicate filtreleridir. Apache koleksiyonlarının yazım eksikliğini gidermek için çok zarif bir yol (Diğer kütüphaneler kullanılamıyorsa).
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
public class Test {
public final static String DEFAULT_COMPONENT = "Default";
enum FilterTest implements Predicate {
Active(false) {
@Override
boolean eval(Test test) {
return test.active;
}
},
DefaultComponent(true) {
@Override
boolean eval(Test test) {
return DEFAULT_COMPONENT.equals(test.component);
}
}
;
private boolean defaultValue;
private FilterTest(boolean defautValue) {
this.defaultValue = defautValue;
}
abstract boolean eval(Test test);
public boolean evaluate(Object o) {
if (o instanceof Test) {
return eval((Test)o);
}
return defaultValue;
}
}
private boolean active = true;
private String component = DEFAULT_COMPONENT;
public static void main(String[] args) {
Collection<Test> tests = new ArrayList<Test>();
tests.add(new Test());
CollectionUtils.filter(tests, FilterTest.Active);
}
}
Bahsedilen stratejilerin yukarısındaki yazı, enums kullanarak strateji modelinin güzel bir hafif uygulamasının size ne kazandırdığını yeterince vurgulamamıştır:
public enum Strategy {
A {
@Override
void execute() {
System.out.print("Executing strategy A");
}
},
B {
@Override
void execute() {
System.out.print("Executing strategy B");
}
};
abstract void execute();
}
Her biri için ayrı bir derleme birimine ihtiyaç duymadan tüm stratejilerinizi tek bir yerde toplayabilirsiniz. Sadece aşağıdakilerle hoş bir dinamik gönderim alırsınız:
Strategy.valueOf("A").execute();
Java'yı neredeyse güzel gevşek bir şekilde yazılmış bir dil gibi okur!
Numaralandırmalar Java Sınıfları gibidir, Yapıcılara, Yöntemlere vb. Sahip olabilirler new EnumName()
. Onlarla yapamayacağınız tek şey . Örnekler, numaralandırma bildiriminizde önceden tanımlanmıştır.
enum Foo extends SomeOtherClass
? Yani normal bir sınıfla aynı şey değil, aslında oldukça farklı.
Başka bir olasılık:
public enum ConditionsToBeSatisfied implements Predicate<Number> {
IS_NOT_NULL(Objects::nonNull, "Item is null"),
IS_NOT_AN_INTEGER(item -> item instanceof Integer, "Item is not an integer"),
IS_POSITIVE(item -> item instanceof Integer && (Integer) item > 0, "Item is negative");
private final Predicate<Number> predicate;
private final String notSatisfiedLogMessage;
ConditionsToBeSatisfied(final Predicate<Number> predicate, final String notSatisfiedLogMessage) {
this.predicate = predicate;
this.notSatisfiedLogMessage = notSatisfiedLogMessage;
}
@Override
public boolean test(final Number item) {
final boolean isNotValid = predicate.negate().test(item);
if (isNotValid) {
log.warn("Invalid {}. Cause: {}", item, notSatisfiedLogMessage);
}
return predicate.test(item);
}
}
ve kullanma:
Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);
Bir jar dosyasında sabitler oluştururken, kullanıcıların enum değerlerini genişletmesine izin vermek genellikle yararlı olur. PropertyFile anahtarları için enumlar kullandık ve takıldık çünkü kimse yenilerini ekleyemedi! Aşağıda çok daha iyi çalışırdı.
Verilen:
public interface Color {
String fetchName();
}
ve:
public class MarkTest {
public static void main(String[] args) {
MarkTest.showColor(Colors.BLUE);
MarkTest.showColor(MyColors.BROWN);
}
private static void showColor(Color c) {
System.out.println(c.fetchName());
}
}
kavanozda bir numaralandırma olabilir:
public enum Colors implements Color {
BLUE, RED, GREEN;
@Override
public String fetchName() {
return this.name();
}
}
ve bir kullanıcı kendi renklerini eklemek için genişletebilir:
public enum MyColors implements Color {
BROWN, GREEN, YELLOW;
@Override
public String fetchName() {
return this.name();
}
}
İşte nedenim ...
Bir Enum değerleri ile bir JavaFX ComboBox doldurdum. Herhangi bir nesnenin arama amaçları için kendini benim uygulama için nasıl tanımlayacağını belirtmek sağlayan bir arabirim, tanımlanabilir (bir yöntem belirleme: tanımlamak) var. Bu arabirim, bir kimlik eşleşmesi için herhangi bir nesne türünün (nesnenin kimlik için hangi alanı kullanabilirse) listelerini taramamı sağlar.
ComboBox listemde kimlik değeri için bir eşleşme bulmak istiyorum. Bu özelliği, Enum değerlerini içeren ComboBox'ımda kullanmak için, Enum'umdaki Tanımlanabilir arabirimi uygulayabilmem gerekir (ki bu durum bir Enum durumunda uygulanması önemsizdir).
Örnek kontrolünü (her strateji bir Singleton'dur) oradan tutmak için bir stratejiyi tanımlayan bir arayüzde bir iç numaralandırma kullandım.
public interface VectorizeStrategy {
/**
* Keep instance control from here.
*
* Concrete classes constructors should be package private.
*/
enum ConcreteStrategy implements VectorizeStrategy {
DEFAULT (new VectorizeImpl());
private final VectorizeStrategy INSTANCE;
ConcreteStrategy(VectorizeStrategy concreteStrategy) {
INSTANCE = concreteStrategy;
}
@Override
public VectorImageGridIntersections processImage(MarvinImage img) {
return INSTANCE.processImage(img);
}
}
/**
* Should perform edge Detection in order to have lines, that can be vectorized.
*
* @param img An Image suitable for edge detection.
*
* @return the VectorImageGridIntersections representing img's vectors
* intersections with the grids.
*/
VectorImageGridIntersections processImage(MarvinImage img);
}
Enum'un stratejiyi uygulaması gerçeği, enum sınıfının ekteki Örneği için proxy olarak hareket etmesine izin vermek için uygundur. bu da arayüzü uygular.
bir tür stratejiEnumProxy: P clent kodu şuna benzer:
VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img);
Arayüzü uygulamadıysa:
VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img);