初始化很多字段 - 构造函数vs方法返回值

时间:2009-07-29 17:28:41

标签: java constructor field

我目前正在开发Java交易卡游戏,类似于旧的神奇宝贝游戏。我现在要做的是以某种方式定义所有卡片,但因为有很多字段需要初始化,我正在考虑其他方法,因为构造函数将非常长并且每张卡片都难以读取。我还必须初始化攻击,这意味着每次我必须基本上创建一个匿名内部类(这个术语是正确的吗?),如下所示:

/**
 * Base set Abra 43/102
 */
public final class Abra extends Pokemon 
{

    public Abra() 
    {
        super(
                new ImageIcon("img/scans/base-set/43-abra.jpg"), 
                "Abra", 
                "Base Set Abra",
                null, 
                Type.PSYCHIC, 
                Type.PSYCHIC, 
                Type.NONE, 
                30, 
                0
        );

        attack1 = new Attack("Psyshock", Type.NORMAL) 
        {

            /**
             * 10 damage. Flip a coin. If heads, the Defending Pokémon is now Paralyzed.
             */
            public void doAttack() 
            {
                damageApplyWeaknessAndResistance(10);
                if (gui.frames.CoinFlipDialog.showCoinFlipFrame() == CoinFlip.COIN_HEADS) 
                {
                    Game.getOpponentPlayer().getActivePokemon().status = Status.Paralyzed;
                }
            }
        };

        attack2 = null;
    }
}

所以我的第二个选择是使用接口和抽象类创建层次结构,这意味着值不会存储在字段中,而是在需要时由方法返回:

public interface Card extends Cloneable, MouseListener, MouseMotionListener
{
    public String getFullName();

    public ImageIcon getSmallIcon();

    public ImageIcon getFullIcon();

}
public interface Pokemon extends Card 
{
    public String getName();

    public int getHPLeft();

    public int getMaxHP();

    public Type getType();

    public Type getWeakness();

    public Type getResistance();

    public int getRetreatCost();

    public Attack getAttack1();

    public Attack getAttack2();
}

public class Abra extends AbstractPokemon 
{

    @Override
    public Attack getAttack1() 
    {
        return new Abra.PsyShock();
    }

    @Override
    public Attack getAttack2() 
    {
        return null;
    }


    @Override
    public int getMaxHP() 
    {
        return 30;
    }

    @Override
    public String getName() 
    {
        return "Base Set Abra";
    } //etc...

所以我的问题是:这些方法中的任何一种是首选还是有更好的方法?

6 个答案:

答案 0 :(得分:5)

我建议使用Builder模式。点击here获取解释。

Josh Bloch推荐:这是他的书“Effective Java 2nd Edition”中的第2项。

答案 1 :(得分:2)

我采取以下方法:

有一个类可以充当任何特定卡的包装器。找到一种方法将每张卡的数据导出到文件或数据库中,并在程序启动时从文件/数据库加载卡。包装器应该能够导入所有特定于卡的数据......包装器将具有所有可用的卡处理功能,并且某些功能可能不适用于所有卡。

替代方案是拥有一个卡片界面,并使用界面设计自定义卡片,每张卡片都有一个新类别。

根据您希望引擎的扩展性/灵活性,决定采取的方法。我个人建议使用包装器类,并将引擎链接到数据库或平面文件。

答案 2 :(得分:0)

我建议使用参数多态,一张卡根据其配置方式运行。您不仅可以减少类的数量(以及扩展,复杂性),而且还可以通过将其特征(包含在结构中,例如,XML)传递给构造函数来配置卡。您还可以在“攻击”类中使用此参数多态概念。

答案 3 :(得分:0)

我肯定会采用数据驱动的方法。每张卡都将共享一组特定属性。你绝对不希望为你的每张卡实现一个新的构建器或java类,特别是如果它们可能有数百个。您将需要某种格式的数据,您可以阅读和解析以创建您的套牌,这样您就可以添加,删除和修改卡片而无需修改Java代码。像xml这样人类可读/可编辑的东西可能效果很好。

当涉及特殊攻击或需要特殊代码处理的其他项目时,难度很大。在这种情况下,您可以使用jython之类的嵌入式脚本引擎,甚至是java 1.6中内置的javascript支持。这样您就可以轻松修改卡片库。现在最大的困难是测试你的特殊攻击脚本。

答案 4 :(得分:0)

  

必须毫无理由地爱那些-1。我知道这是一个不同寻常的观点,但我已经在这里工作了几十年,有时我不认为典型的方式是最好的方式。如果你真的认为这是错的,为什么不说为什么呢? MEH。

我不是那个给你打分的人,但我对我为什么会这样做的看法如下。

虽然您使用哈希表存储内部数据的想法是可行的,但它并不是原始海报意图的最佳方法。他的应用程序(或游戏)涉及基于游戏中卡片属性的大量操作;它不仅仅是将属性保存到数据库并从数据库中读取它们。在这种情况下,具有适当含义的类型属性将使得更容易执行游戏逻辑。请记住,OOD / OOP是关于正确的封装和具有凝聚力和有意义的结构。

答案 5 :(得分:-1)

为什么不将关于单个实体的所有信息放在哈希表中并将其包装在类中?

您仍然可以获得封装和所有优点,但您也可以轻松编写代码以将数据绑定到GUI或数据库,而无需借助反射。

你仍然可以在需要与其他代码进行交互的地方编写setter和getter,但是在你正在谈论的大多数字段的应用程序中都是从未特别操作的纯数据(大多数代码访问字段是一般副本和粘贴,并非真正特定于任何领域。)

你也可以使用像set这样的单一方法(“Name”,“Abra”);或name = get(“名称”);访问散列中的任何字段而无需编写数十个setter和getter ......

我在编写了数百个属性类型屏幕后得出了这个结论,其中数据只是从数据库中提取,在屏幕上显示,修改,然后发送回数据库。这些天我的目标是,当我这样做时,我应该能够在没有一行代码的情况下为流程添加新控件 - 只需修改元数据。

绑定到屏幕和数据库甚至验证都可以设置为元数据,然后一切都变得更加容易......

(更容易假设你像我一样对复制和粘贴不利......)