回答:
列挙型は、パッシブセット(色など)を表す必要はありません。彼らは、機能性と、より複雑なオブジェクトを表すことができ、そのため、あなたは、おそらくこれらにさらに機能を追加したいです-あなたのようなインターフェースがあり、たとえばPrintable
、Reportable
これらをサポートするなどして部品を。
これが1つの例です(同様の/より良いものは、Effective Java 2nd Editionにあります)。
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 :-/
}
次に、単純演算子と複合演算子の両方のリストを取得します。
List<Operator> operators = new ArrayList<Operator>();
operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));
したがって、ここではインターフェイスを使用して、拡張可能な列挙型をシミュレートします(インターフェイスを使用しないと実現できません)。
Comparable
いくつかの人々によって与えられた例はここにいるので、間違っているEnum
すでに実装していること。オーバーライドすることもできません。
より良い例は、たとえばデータ型を定義するインターフェースを持つことです。列挙型を使用して単純な型を実装し、通常のクラスで複雑な型を実装できます。
interface DataType {
// methods here
}
enum SimpleDataType implements DataType {
INTEGER, STRING;
// implement methods
}
class IdentifierDataType implements DataType {
// implement interface and maybe add more specific methods
}
よく使うケースがあります。IdUtil
非常にシンプルなIdentifiable
インターフェースを実装するオブジェクトを操作するための静的メソッドを持つクラスがあります。
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;
}
}
私が作成した場合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;
}
}
それから私はそれをid
この方法で得ることができます:
MyEnum e = IdUtil.get(MyEnum.class, 1);
Enumはインターフェイスを実装できるため、シングルトンパターンの厳密な適用に使用できます。標準クラスをシングルトンにしようとすると...
シングルトンとしての列挙型は、これらのセキュリティ問題の防止に役立ちます。これは、Enumsをクラスとして機能させ、インターフェースを実装させる理由の1つであった可能性があります。ただの推測です。
詳細については、javaの/programming/427902/java-enum-singletonおよびSingletonクラスを参照してください。
for inheriting from your singleton and overriding your singleton's methods with something else
。あなたはそれfinal class
を防ぐために単に使うことができます
拡張性のために必要です。開発したAPIを誰かが使用する場合、定義する列挙型は静的です。追加または変更することはできません。ただし、インターフェースの実装を許可すると、APIを使用する人は同じインターフェースを使用して独自の列挙型を開発できます。次に、この列挙型を、標準列挙型と一緒に列挙型をまとめる列挙型マネージャーに登録できます。
編集:@Helperメソッドはこれの完璧な例を持っています。他のライブラリーに新しいオペレーターを定義させ、マネージャー・クラスに「ねえ、この列挙型は存在する-登録する」と伝えることを考えてください。それ以外の場合は、独自のコードでのみ演算子を定義できます-拡張性はありません。
列挙型は変装したクラスにすぎないため、ほとんどの場合、列挙型を使用してクラスで実行できることは何でも実行できます。
enumがインターフェイスを実装できない理由を考えることはできませんが、同時に、それらを行う理由も考えられません。
インターフェースやメソッドなどを列挙型に追加し始めたら、それをクラスにすることを検討する必要があります。もちろん、非伝統的な列挙型のことを行う正当なケースがあると私は確信しています。制限は人工的なものであるため、そこで人々が望むことをできるようにしたいと思います。
これの最も一般的な使用法は、2つの列挙型の値を1つのグループにマージし、それらを同様に扱うことです。たとえば、Fruits and Vegatablesに参加する方法をご覧ください。
enumをインターフェイスで使用するのに最適な使用例の1つは、述語フィルターです。これは、Apacheコレクションのタイプの欠如を修正する非常にエレガントな方法です(他のライブラリが使用されていない場合)。
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);
}
}
戦略について述べた上記の投稿では、enumsを使用した戦略パターンの軽量で優れた実装によって、どのような効果が得られるかを十分に強調していませんでした。
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();
}
戦略ごとに個別のコンパイルユニットを必要とせずに、すべての戦略を1か所にまとめることができます。あなただけで素晴らしい動的ディスパッチを取得します:
Strategy.valueOf("A").execute();
緩やかに型付けされた素晴らしい言語のようにJavaを読み取らせます
列挙型はJavaクラスのようなもので、コンストラクター、メソッドなどを持つことができます。列挙型で実行できないのは、だけですnew EnumName()
。インスタンスは、列挙型宣言で事前定義されています。
enum Foo extends SomeOtherClass
ですか?したがって、通常のクラスとまったく同じではなく、実際にはかなり異なります。
別の可能性:
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);
}
}
そして使用:
Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);
jarファイルに定数を作成する場合、ユーザーが列挙値を拡張できるようにすると便利な場合があります。PropertyFileキーに列挙型を使用しましたが、誰も新しいものを追加できなかったために行き詰まりました!以下ははるかにうまく機能します。
与えられた:
public interface Color {
String fetchName();
}
そして:
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());
}
}
jarに1つの列挙型を含めることができます。
public enum Colors implements Color {
BLUE, RED, GREEN;
@Override
public String fetchName() {
return this.name();
}
}
ユーザーはそれを拡張して自分の色を追加することができます。
public enum MyColors implements Color {
BROWN, GREEN, YELLOW;
@Override
public String fetchName() {
return this.name();
}
}
ここに私の理由があります...
Enumの値をJavaFX ComboBoxに入力しました。Identifiable(1つのメソッドを指定する:識別)のインターフェイスを持っています。これにより、オブジェクトが検索目的でアプリケーションに対して自分自身を識別する方法を指定できます。このインターフェイスを使用すると、任意のタイプのオブジェクト(オブジェクトがIDに使用できるフィールド)のリストをスキャンして、IDの一致を確認できます。
ComboBoxリストでID値の一致を見つけたいのですが。Enum値を含むComboBoxでこの機能を使用するには、EnumにIdentifiableインターフェースを実装できる必要があります(これは、Enumの場合は簡単に実装できます)。
そこからインスタンス制御(各戦略はシングルトン)を維持するための戦略を記述するインターフェイスで内部列挙型を使用しました。
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が戦略を実装するという事実は、enumクラスがその囲まれたインスタンスのプロキシとして機能できるようにするのに便利です。インターフェースも実装しています。
それは一種のStrategyEnumProxyです:Pクライアントコードは次のようになります:
VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img);
それがインターフェイスを実装していなかった場合、それはそうでした:
VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img);