2015-11-24 53 views
8

我使用枚舉來定義可以添加到產品(自定義徽標,顏色等)的幾種變化。每個變體都有幾個選項(ID,兩種語言的描述,過程中的變化,價格等)。它有方法來進一步定義變體(例如應使用哪種顏色)或覆蓋某些選項。一個產品可以在ArrayList中存儲零個,一個或多個變體。另外,一種產品可以多次應用於一種產品。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你肯定**可**具有枚舉的函數和屬性。 –

+3

如何使用buider模式(https://en.wikipedia.org/wiki/Builder_pattern)而不是枚舉? – Aurelien

回答

6

不,枚舉不太適合描述相似但具有不同狀態的對象。

枚舉常量是靜態。您沒有兩個不同的TEST1實例。你只有一個。在您的示例中引用TEST2的兩個列表條目都引用同一個實例。這不是一個副本,它是第二個參考。

要使實例相似但狀態稍有不同,應聲明,而不是枚舉。您可以使用枚舉來描述變體的類型(例如COLOR_VARIATION,CUSTOM_LOGO)。你可以有兩個不同的類來擴展名爲Variation的類,或者直接使用它 - 取決於實現細節是否不同。但是,您將使用new Variation(...)或使用靜態工廠方法創建Variation的新實例,然後每個Variation實例在其字段中可以有不同的值集合,即使它們都具有相同的「變體類型」。

8

不,你不能這樣做與枚舉。每個枚舉值總是隻有一個實例。如果您更改枚舉數據(例如使用您的setOpn()方法之一),它將在全局範圍內更改,因爲只有一個。

最好使數據在enum上不可變。然後,對於可變選項,您可以將ArrayList與每個有選項的東西關聯起來,併爲其指定一個枚舉。

你可以做這樣的:

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

只有一個每個枚舉值的實例。把它們看作編譯器強制執行的全局變量。

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引用無效。其次,當您參考TestEnum.TEST2時,您在兩個塊中指向相同的值 - 這意味着稍後調用setOp會覆蓋以前的值。

1

通常,根據定義,枚舉是不變的。通過將setter添加到您的枚舉中,可以使其變體。

至於你的問題,這是因爲你對陣列中的TEST2有相同的參考。既然它是一個參考,第二個和第三個元素是完全相同的。因此,如果您修改TEST2元素中的任何一個元素,則其他參考將反映該更改。

至於測試,您可以將分配線(enumVar.setOp1)從第三個元素切換到第二個元素,您將看到相同的行爲。

這就像你將枚舉轉換爲對象。

8

此頁面上的其他答案可能都是正確的,但可能無法真正幫助您解決問題。

而不是一個枚舉,嘗試實現一個普通的舊類,但包括clone()方法。然後,您可以創建幾個代表默認產品配置的「默認」類實例。當用戶選擇某個產品配置時,您可以在主對象上調用clone(),然後您可以使用常規設置器從此處修改對象。

查看原型設計模式。整個想法是使用這些「主」對象來創建新的副本,然後可以更改。我想這可能是你要找的更多。 https://en.wikipedia.org/wiki/Prototype_pattern

+2

這是一個很好的創意答案。它解決了OP的需求,而不受其假設限制。 –

+2

請勿使用'clone'和'Cloneable'。不建議使用'clone'和'Cloneable'。機制被打破,Josh Bloch徹底毆打。人們總是可以創建一個複製構造函數,或者添加一些創建「預先組裝」實例的靜態工廠方法。 – RealSkeptic

相關問題