2015-11-24 127 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

相关问题