我有一个班级
var data = [{
"N": "3M",
"a": "<img src=\"/img/samples/flag_red.gif\" alt=\"red\" height=\"16\" width=\"16\" border=\"0\"/>",
"c": "<img src=\"/img/samples/flag_red.gif\" alt=\"red\" height=\"16\" width=\"16\" border=\"0\"/>",
"r": "<img src=\"/img/samples/flag_red.gif\" alt=\"red\" height=\"16\" width=\"16\" border=\"0\"/>",
"p": "<img src=\"https://a.na7.visual.force.com/resource/1260007793000/a/iconset/gray.gif\" alt=\" \" height=\"16\" width=\"1\" border=\"0\"/>"
}, {
"N": "ABC corp",
"a": "<img src=\"/img/samples/flag_red.gif\" alt=\"red\" height=\"16\" width=\"16\" border=\"0\"/>",
"c": "<img src=\"/img/samples/flag_red.gif\" alt=\"red\" height=\"16\" width=\"16\" border=\"0\"/>",
"r": "<img src=\"/img/samples/flag_green.gif\" alt=\"green\" height=\"16\" width=\"16\" border=\"0\"/>",
"p": "<img src=\"https://a.na7.visual.force.com/resource/1260007793000/a/iconset/gray.gif\" alt=\" \" height=\"16\" width=\"1\" border=\"0\"/>"
}];
var modified = data.reduce(function (outArr, entry) {
var outObj = {};
for (key in entry) {
if (entry.hasOwnProperty(key)) {
var item = entry[key];
var node = document.createElement("div");
node.innerHTML = item;
var img = node.querySelector("img");
outObj[key] = img ? img.alt : item;
}
}
outArr.push(outObj);
return outArr;
}, []); //[{"N":"3M","a":"red","c":"red","r":"red","p":" "},{"N":"ABC corp","a":"red","c":"red","r":"green","p":" "}]
编辑(更清楚):enumA和objectB是相互依赖的。 MyObjectB有3个子类。并且MyEnumA的每个值都与MyObjectB
的子类中的一个对象相关由于MyObjectB有3个子类,因此objectB可以是3种类型。 MyEnumA有很多值(~30,因为我只需要他们的文本值,不能想到除枚举之外的任何其他选项,如果枚举不应该有这么多值,请纠正我。)
因此,MyEnumA和MyObjectB可以有30x3 = 90种组合,但并非所有90种组合都有效。这就是我被困的地方。
解决这个问题的最佳方法是什么?我能想到的几个选项是:
1)每当创建一个MyCompleteObject实例时,我应检查enumA和objectB是否彼此一致,如果它们不一致则抛出异常(对这种方法不太满意)。
2)使用enumA和objectB的不同组合创建许多子类。同样,似乎并不是一个很有希望的解决方案,因为将根据不同的组合enumA和objectB创建许多子类。
更新1)
在阅读各种答案后我能想到的第三种方法是:
3)首先制作可扩展的rick枚举类型,如@ scottb的答案所述。然后我想我可以在MyCompleteObject类中创建3个不同的构造函数: EnumA,EnumB和EnumC是我的枚举,根据它们的有效性分为3个子类MyObjectB(@ scottb&#39;答案)。 MyObjectBFirst,MyObjectBSecond和MyObjectBThird是MyObjectB的三个子类。
public class MyCompleteObject {
private MyEnumA enumA;
private MyObjectB objectB;
}
这可以确保编译时检查。但是,有3个不同的构造函数。我也查看了构建器模式但不适合它。它的目的是添加可选参数,但在这里我有条件参数,所有都是必需的。
谢谢!
答案 0 :(得分:1)
使您的类中的EnumA值不可变(无setter),并强制用户在构造函数(或通过工厂)中提供它。这会强制构造的类始终使用相同的EnumA值。然后,您可以在构造函数或其setter中对ObjectB强制执行类类型。
public class MyCompleteObject {
private MyEnumA enumA;
private MyObjectB objectB;
public MyCompleteObject(MyEnumA enumA) { this.enumA = enumA; }
public void setObjectB(MyObjectB objectB) {
if(objectB.getClass() == enumA.getValidClassName()) {
this.objectB = objectB;
} else {
throw new InvallidArgumentException();
}
}
}
如果您决定使用子类,我建议使用一个基本接口,其中有三个抽象类实现它 - 每个可能类型的ObjectB一个。然后,您可以为表示给定ObjectB的每个EnumA值扩展特定的抽象类。
public class MyObjectB {};
//Three sub classes of MyObjectB follows
public class MyObjectBType1 extends MyObjectB {};
public class MyObjectBType2 extends MyObjectB {};
public class MyObjectBType3 extends MyObjectB {};
// enum with constructor parameter that tells
// which enum value is compatible with which subclass of MyObjectB
public enum MyEnum {
A (MyObjectBType1.class),
B (MyObjectBType1.class),
C (MyObjectBType2.class),
D (MyObjectBType3.class),
E (MyObjectBType3.class),
;
private Class<? extends MyObjectB> validClassName;
MyEnum(Class<? extends MyObjectB> cls) {
this.validClassName = cls;
}
public Class<? extends MyObjectB> getValidClassName() {
return validClassName;
}
}
答案 1 :(得分:1)
对于可扩展丰富的枚举类型来说,这听起来是一个很好的用例:
public enum EnumA implements MyEnumType {
COMMON_TO_A_1,
:
:
COMMON_TO_A_N;
@Override public void commonMethod1() { ... }
:
}
public enum EnumB implements MyEnumType {
COMMON_TO_B_1,
:
:
COMMON_TO_B_N;
@Override public void commonMethod1() { ... }
:
}
public interface MyEnumType {
void commonMethod1();
:
:
int commonMethodN(String myParam);
}
通过使用MyEnumType作为类型名称,您将能够传入任何枚举组并对它们执行常见的类型安全操作。 Java中的枚举工具是健壮且类型安全的,并且通常优于滚动自己的枚举类。我建议尽可能使用枚举工具。
缺点是这不是继承模式,并且没有常见枚举的超集。有时,根据您的需要,可以在代码中模拟,而不会有太多麻烦。例如,您可以定义另一个枚举,它提供“基本枚举”的类文字,以便您可以始终在您执行的所有操作中引用这些常量,以及使用接口类型传递的任何枚举组。 / p>
另一个缺点是,当您通过接口类型传递枚举常量时,它会失去其作为Java枚举工具成员的身份。这意味着你将无法使用类似EnumMap和EnumSet的东西与你的接口类型常量。有这种限制的解决方法,但它们可能并不总是干净实现。
答案 2 :(得分:1)
既然你提到了你想要编译时检查解决方案。这是我能想到的一种方式。
我建议您将MyOBjectB的子类注入MyEnumA定义。 让我们假设MyEnumA在现实生活中可以是动物,而MyObjectB在现实生活中是一种动物。因此,某些动物将属于某种类型,任何其他组合都将无效。
public class Test {
enum Animal {
PIGEON(new Flyers()), EAGLE(new Flyers()), //flyers
SNAKE(new Crawlers()), CROCODILE(new Crawlers()), //crawlers
COW(new Walkers()), DOG(new Walkers()); //walkers
private AnimalCharacteristics characteristics;
private Animal(AnimalCharacteristics characteristics) {
this.characteristics = characteristics;
}
public AnimalCharacteristics getCharacteristics() {
return characteristics;
}
}
interface AnimalCharacteristics {
void setWeight(double kgs);
};
public static class Flyers implements AnimalCharacteristics {
@Override
public void setWeight(double kgs) {
// do something
}
}
public static class Crawlers implements AnimalCharacteristics {
@Override
public void setWeight(double kgs) {
// do something
}
}
public static class Walkers implements AnimalCharacteristics {
@Override
public void setWeight(double kgs) {
// do something
}
}
public static void main(String[] args) {
System.out.println(Animal.PIGEON.getCharacteristics() instanceof Flyers); //true
System.out.println(Animal.PIGEON.getCharacteristics() instanceof Crawlers); //false
//Make updates
Animal.PIGEON.getCharacteristics().setWeight(0.75);
Animal.COW.getCharacteristics().setWeight(240.00);
}
}
<强>更新强> 下面更新了代码,因为OP留下了一条评论,说新的实例更可取而不是重新使用AnimalCharacteristics的实例
public class Test {
enum Animal {
PIGEON(Flyers.class), EAGLE(Flyers.class), //flyers
SNAKE(Crawlers.class), CROCODILE(Crawlers.class), //crawlers
COW(Walkers.class), DOG(Walkers.class); //walkers
private Class<? extends AnimalCharacteristics> characteristicsClass;
private Animal(Class<? extends AnimalCharacteristics> characteristicsClass) {
this.characteristicsClass = characteristicsClass;
}
public AnimalCharacteristics getCharacteristics() {
try {
System.out.println(" ~~~ Creating new instance of: " +
characteristicsClass.getCanonicalName());
return characteristicsClass.newInstance();
} catch (Exception e) {
System.out.println(" ~~~ Exception while creating instance: "
+ e.getMessage());
return null;
}
}
}
interface AnimalCharacteristics {
AnimalCharacteristics setWeight(double kgs);
};
public static class Flyers implements AnimalCharacteristics {
@Override
public AnimalCharacteristics setWeight(double kgs) {
return this;
}
}
public static class Crawlers implements AnimalCharacteristics {
@Override
public AnimalCharacteristics setWeight(double kgs) {
return this;
}
}
public static class Walkers implements AnimalCharacteristics {
@Override
public AnimalCharacteristics setWeight(double kgs) {
return this;
}
}
public static void main(String[] args) {
AnimalCharacteristics pigeon = Animal.PIGEON.getCharacteristics();
System.out.println("Is pigeon a flyer => "
+ (pigeon instanceof Flyers)); //true
System.out.println("Is pigeon a crawler => "
+ (pigeon instanceof Crawlers)); //false
//Make updates
pigeon.setWeight(0.75);
AnimalCharacteristics cow = Animal.COW.getCharacteristics().setWeight(240.00);
System.out.println("Cow is of type:" + cow.getClass().getCanonicalName());
}
}
如果运行上面的代码将产生以下输出:
~~~ Creating new instance of: Test.Flyers
Is pigeon a flyer => true
Is pigeon a crawler => false
~~~ Creating new instance of: Test.Walkers
Cow is of type:Test.Walkers