2015-11-24 14 views
8

商品に追加できるいくつかのバリエーション(カスタムロゴ、色など)を定義するためにenumを使用します。各バリエーションにはいくつかのオプションがあります(ID、2つの言語での説明、プロセスの変更、価格など)。バリエーションをさらに定義する方法(たとえば、どの色を使用するかなど)や特定のオプションを上書きする方法があります。 1つの製品は、ArrayListに格納されている0個、1個または複数のバリエーションを持つことができます。また、1つの製品に複数のバリエーションを複数回適用することもできます。異なる値を持つJavaの同じ列挙型

私が一度だけバリエーションを使用する限り、すべては問題ありません。しかし、私がそれを複数回使用する場合、すべてが同じオプションを得るように見えます。

サンプルコード:

TestClass.java:

import java.util.ArrayList; 

public class TestClass { 
public static void main(String[] args) { 
    ArrayList<TestEnum> enums = new ArrayList<>(); 
    TestEnum enumVar; 

    enumVar = TestEnum.TEST1; 
    enums.add(enumVar); 
    enumVar = null; 

    enumVar = TestEnum.TEST2; 
    enums.add(enumVar); 
    enumVar = null; 

    enumVar = TestEnum.TEST2; 
    enumVar.setOp1("new op21"); 
    enumVar.setOp2("new op22"); 
    enumVar.setOp3("new op23"); 
    enums.add(enumVar); 
    enumVar = null; 

    enums.forEach((element) -> { 
     System.out.println("op1: " + element.getOp1() + "; op2: " + element.getOp2() + "; op3: " + element.getOp3()); 
     /* 
     Expecting: 
     op1: op11; op2: op12; op3: op13 
     op1: op21; op2: op22; op3: op23 
     op1: new op21; op2: new op22; op3: new op23 

     Output: 
     op1: op11; op2: op12; op3: op13 
     op1: new op21; op2: new op22; op3: new op23 
     op1: new op21; op2: new op22; op3: new op23 
     */ 
    }); 
} 
} 

TestEnum.java:

public enum TestEnum { 
TEST1("op11", "op12", "op13"), 
TEST2("op21", "op22", "op23"), 
TEST3("op31", "op32", "op33"), 
TEST4("op41", "op42", "op43"), 
TEST5("op51", "op52", "op53"); 

private String op1; 
private String op2; 
private String op3; 

TestEnum(String op1, String op2, String op3) { 
    this.op1 = op1; 
    this.op2 = op2; 
    this.op3 = op3; 
} 

public void setOp1(String op1) { 
    this.op1 = op1; 
} 

public String getOp1() { 
    return this.op1; 
} 

public void setOp2(String op2) { 
    this.op2 = op2; 
} 

public String getOp2() { 
    return this.op2; 
} 

public void setOp3(String op3) { 
    this.op3 = op3; 
} 

public String getOp3() { 
    return this.op3; 
} 
} 

それは私が列挙して心を持っているものを行うことは可能ですか?

「はい」の場合、どうしたらよいですか?おそらく、特定の状態で列挙型のコピーを作成する可能性はありますか?

+0

@tanjirあなたは間違いなく**機能と属性をenumに持つことができます。 –

+3

enumの代わりにbuiderパターン(https://en.wikipedia.org/wiki/Builder_pattern)を使用するのはどうですか? – Aurelien

答えて

6

いいえ、enumは、類似しているが状態が異なるオブジェクトを説明するのには適していません。

列挙定数はスタティックです。 TEST1の2つの異なるインスタンスがありません。あなたはただ一つしか持っていません。あなたの例ではTEST2を参照する両方のリストエントリは、同じインスタンスを参照してください。それはコピーではなく、第2の参考資料です。

類似しているが状態が少しずつ異なるインスタンスを持つには、クラスを宣言する必要があります。列挙型ではありません。列挙型を使用してバリエーションのタイプを記述することができます(例:COLOR_VARIATIONCUSTOM_LOGO)。 Variationというクラスを拡張する2つの異なるクラスを持つことも、実装の詳細が異なるかどうかに応じて直接使用することもできます。しかし、new Variation(...)を使用するか、または静的ファクトリメソッドを使用してVariationの新しいインスタンスを作成し、それぞれが同じ「バリエーションタイプ」であっても、各Variationインスタンスはそのフィールドに異なる値セットを持つことができます。

8

いいえ、あなたはenumでこれを行うことはできません。常に各enum値のインスタンスは1つだけです。列挙型のデータ(たとえば、setOpn()メソッドの1つ)を変更すると、そのデータは1つしかないため、グローバルに変更されます。

列挙型のデータを不変にすることをお勧めします。次に、変数のオプションのために、ArrayListをオプションを持つそれぞれのものに関連付けて、列挙型の1つを割り当てます。

あなたはこのようにそれを行うことができます:

public class ThingWithOptionsAndEnum { 
    private final TestEnum myBaseOptions; 
    private final ArrayList<String> myAdditionalOptions = new ArrayList<>(); 

    public ThingWithOptionsAndEnum(final TestEnum base, String... options) { 
     this.myBaseOptions = base; 
     if (options != null) { 
      for (String option : options) { 
       myAdditionalOptions.add(option); 
      } 
     } 
    } 
} 
2

各列挙型の値のインスタンスが1つだけあります。コンパイラによって強制されるグローバル変数と考えることができます。

enumVar = TestEnum.TEST2; 
enums.add(enumVar); 
enumVar = null; 

enumVar = TestEnum.TEST2; 
enumVar.setOp1("new op21"); 
enumVar.setOp2("new op22"); 
enumVar.setOp3("new op23"); 
enums.add(enumVar); 
enumVar = null; 

まず、明示的enumVar参照をゼロにすることは何もしません。第2に、TestEnum.TEST2を参照すると、両方のブロックで同じ値を指しています。つまり、後でsetOpを呼び出すと、以前の値が上書きされます。

1

通常、enumは定義によって不変です。列挙型にセッターを追加することで、それを変形することができます。

あなたの質問には、あなたの配列にTEST2と同じ参照があるからです。それは参照であるため、2番目と3番目の要素はまったく同じです。したがって、TEST2要素のいずれかを変更した場合、他の参照は変更を反映します。

これをテストするには、割り当て行(enumVar.setOp1)を3番目の要素から2番目の要素に切り替えると、同じ動作が表示されます。

これは、列挙型をオブジェクトに変換したようなものです。

8

このページのその他の回答はすべて正しいと思われますが、実際に問題を解決するのには役立たない場合があります。

列挙型ではなく、普通の古いクラスを実装してみてください。ただし、clone()メソッドを実装してください。次に、それぞれがデフォルトの製品構成を表すクラスのいくつかの「デフォルト」インスタンスを作成できます。ユーザーが特定の製品構成を選択すると、マスターオブジェクトでclone()を呼び出した後、通常のセッターを使用してここからオブジェクトを変更できます。

プロトタイプのデザインパターンを確認してください。全体のアイデアは、これらの「マスター」オブジェクトを使用して新しいコピーを作成し、それを変更することです。私はこれがもう少しあなたが探しているものだと思う。 https://en.wikipedia.org/wiki/Prototype_pattern

+2

これは良い創造的な答えです。彼らは、彼らの前提に縛られることなく、OPのニーズに対応します。 –

+2

'clone'と' Cloneable'を使わないでください。 'clone'と' Cloneable'を使うことはお勧めしません。メカニズムは壊れていて、Josh Blochによって完全に殴られました。コピーコンストラクタを作成することも、「事前組み立て」されたインスタンスを作成する静的なファクトリメソッドをいくつか追加することもできます。 – RealSkeptic