我正在尝试将Hearthstone卡片重新创建为Java中的对象,但我在以高效且有效的方式进行此操作时遇到了麻烦。
所有卡片都有一些常用属性,如“名称”。但问题在于,大约有300张牌可以生成,每张卡可能有或没有大约30种不同的能力。现在,我是否必须创建一个基本的卡片类,将所有可能的能力设置为false,然后将其所有特定的能力参数设置为true?这种方法似乎对所有吸气剂和一些能力需要指定的所有额外信息非常混乱......所以我的问题是,是否有更好的方法来解决这类问题?
我想创建这些卡片对象,这样我只是“添加”特定的能力作为字段,但我无法弄清楚如何以一种好的方式做到这一点。
感谢您的帮助!
答案 0 :(得分:0)
在每种情况下都不需要设计模式,因此请注意不要过度使用它们,但似乎它们可以在这里帮助您。 Dave提到的两种解决方案都可以起作用,但是将每种能力作为一个对象的问题在于它要求你制作尽可能多的课程。此外,如果每个能力都是一个简单的变量,那么为所有这些变量创建类可能会过度,特别是因为很多类很难维护。虽然从接口继承这些功能在某种程度上有助于维护,但我认为可以在构建器模式中找到更简单的解决方案。
我不会在这里详细解释,但这里的tutorial似乎相当简单。它的基本目的是
对于您的特定示例,它看起来像这样:
public class Card
{
private final String name;
private final Ability soundAbility;
private final Ability animationAbility;
private final Ability customMessageAbility;
private final String technology;
// The constructor is private in this case to restrict instantiation to the builder.
private Card(CardBuilder builder)
{
this.name = builder.name;
this.soundAbility = builder.soundAbility;
this.animationAbility = builder.animationAbility;
this.customMessageAbility = builder.customMessageAbility;
this.technology = builder.technology;
}
// Getters
public String getName()
{
return this.name;
}
public Ability getSoundAbility()
{
return this.soundAbility;
}
// ... More getters and stuff ...
@Override
public String toString()
{
String text = "";
text += this.name + ":";
text += "\n\t" + this.soundAbility;
text += "\n\t" + this.animationAbility;
text += "\n\t" + this.customMessageAbility;
text += "\n\tI have the ability of " + this.technology + "!";
return text;
}
// Nested builder class
public static class CardBuilder
{
private final String name;
private Ability soundAbility;
private Ability animationAbility;
private Ability customMessageAbility;
private String technology;
public CardBuilder(String name)
{
this.name = name;
}
public CardBuilder soundAbility(Ability soundAbility)
{
this.soundAbility = soundAbility;
return this;
}
public CardBuilder animationAbility(Ability animationAbility)
{
this.animationAbility = animationAbility;
return this;
}
public CardBuilder customMessageAbility(Ability customMessageAbility)
{
this.customMessageAbility = customMessageAbility;
return this;
}
public CardBuilder technology(String technology)
{
this.technology = technology;
return this;
}
public Card build()
{
return new Card(this);
}
}
}
然后运行程序:
package builderTest;
class BuilderMain
{
public static void main(String[] args)
{
// Initialize ability objects.
Ability a1 = new SoundAbility();
Ability a2 = new AnimationAbility();
Ability a3 = new CustomMessageAbility();
// Build card
Card card = new Card.CardBuilder("Birthday Card")
.soundAbility(a1)
.animationAbility(a2)
.customMessageAbility(a3)
.technology("Flash")
.build();
System.out.println(card);
}
}
输出将是:
Birthday Card:
I have the ability of sound!
I have the ability of animation!
I have the ability of customizing messages!
I have the ability of Flash!
请记住,我在没有太多背景的情况下工作,所以您需要的可能会有很大不同。
答案 1 :(得分:0)
虽然以前的答案非常好,但还有另一种实现此对象创建的方法
有很多可选字段
在处理数据库复杂性和Command design pattern时,我发现自己处于类似情况。如您所知,某些表列值是必需的 - 有些则不是。我正在使用这个Effective Java book 对于这种情况。
所以,这里有用的是Consider a builder when faced with many constructor parameters
。通过这样做,你可以避免
首先, Telescoping构造函数模式(不能很好地扩展) - 它可以工作,但是当有很多参数时很难编写客户端代码,并且更难以阅读它。
第二, JavaBeans模式,这很好,但允许不一致并强制要求可变性。它可能在其构造的中途处于不一致的状态,并且排除了使类不可变的可能性。
使用的Builder模式模拟Ada和Python中的命名可选参数。像构造函数一样,构建器可以对其参数强加不变量。但是,在将构建器中的参数复制到对象并检查它们之后,检查它们是 critical 对象字段而不是构建器字段。
干杯。