Инициализация множества полей - конструктор и метод возвращают значения - PullRequest
1 голос
/ 29 июля 2009

В настоящее время я работаю над карточной игрой на Java, похожей на старую Pokémon. Теперь я хочу как-то определить все карточки, но поскольку есть много полей, которые нужно инициализировать, я думаю об альтернативных способах, потому что конструктор будет очень длинным и трудно читаемым для каждой карточки , Я также должен инициализировать атаки, что означает, что я должен в основном создавать анонимный внутренний класс (термин правильный?) Каждый раз, например так:

/**
 * 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 ]

5 голосов
/ 29 июля 2009

Я рекомендую использовать шаблон Builder. Нажмите здесь для объяснения.

Это рекомендовано Джошем Блохом: это пункт 2 в его книге Effective Java 2nd Edition.

2 голосов
/ 29 июля 2009

Я бы выбрал следующий подход:

Имейте класс, который может выступать в качестве обертки для любой конкретной карты. Найдите способ экспортировать данные для каждой карты в файл или базу данных и загрузите карты из файлов / базы данных при запуске программы. Упаковщик должен иметь возможность импортировать все данные, относящиеся к карточке ... упаковщик будет иметь все доступные функции обработки карточек, и некоторые функции могут быть неприменимы ко всем карточкам.

Альтернативой может быть интерфейс карты, и вы создаете пользовательские карты, используя интерфейс, один новый класс для каждой карты.

В зависимости от того, насколько расширяемым / гибким вы хотите, чтобы ваш двигатель был, выберите подход. Я лично рекомендую использовать класс-оболочку и связать ваш движок с базой данных или плоским файлом.

0 голосов
/ 29 июля 2009

Должен любить эти -1 без оправдания. Я знаю, что это необычная точка зрения, но я занимался этим десятилетиями, и иногда я не думаю, что типичный способ - лучший. Если вы действительно думаете, что это неправильно, почему бы не сказать, почему? Мех.

Я не тот, кто пренебрег вами, но мое мнение о том, почему я так поступил, заключается в следующем.

Хотя ваша идея использовать хеш-таблицу для хранения внутренних данных осуществима, это не лучший подход к тому, что намеревается использовать оригинальный плакат. Его приложение (или игра) включает в себя множество операций, основанных на атрибутах карты в игре; речь идет не только о сохранении атрибутов и чтении их из базы данных. В таком случае наличие атрибутов с правильным значением облегчит выполнение логики игры. Помните, что OOD / OOP о правильной инкапсуляции и имеет целостную и содержательную структуру.

0 голосов
/ 29 июля 2009

Я бы определенно использовал подход, основанный на данных. Каждая карта собирается поделиться определенным набором атрибутов. Вы определенно не хотите реализовывать новый конструктор или класс Java для каждой из ваших карт, особенно если их может быть несколько сотен. Вам понадобятся ваши данные в каком-то формате, который вы можете прочитать и проанализировать, чтобы создать колоду, чтобы вы могли добавлять, удалять и изменять карты без необходимости изменения кода Java. Что-то читаемое / редактируемое человеком, такое как xml, вероятно, будет работать очень хорошо.

Сложность будет в том, что касается специальных атак или других предметов, для обработки которых требуется специальный код. В этом случае вы можете использовать встроенный механизм сценариев, такой как jython или даже встроенную поддержку javascript в java 1.6 . Таким образом, вы можете легко изменить библиотеку карт. Самой большой трудностью сейчас будет тестирование ваших специальных сценариев атаки.

0 голосов
/ 29 июля 2009

Я бы рекомендовал использовать параметрический полиморфизм, когда одна карта ведет себя в соответствии с тем, как она настроена. Вы не только сократите количество классов (и, соответственно, сложность), но также сможете конфигурировать карты, передавая их характеристики (например, в структуре, скажем, XML) конструктору. Вы также можете использовать эту концепцию параметрического полиморфизма на классах «атаки».

0 голосов
/ 29 июля 2009

Почему бы просто не поместить всю информацию об отдельной сущности в хеш-таблицу и обернуть ее в классе?

Вы по-прежнему получаете инкапсуляцию и все приятные преимущества, но вы также можете легко написать код для привязки ваших данных к графическому интерфейсу или базе данных, не прибегая к рефлексии.

Вы по-прежнему МОЖЕТЕ писать сеттеры и геттеры там, где они необходимы для взаимодействия с другим кодом, но в приложениях, о которых вы говорите, большинство полей - это чистые данные, которые никогда специально не манипулируются (большинство полей, обращающихся к коду, являются общими копиями и вставить, не очень специфично для какого-либо поля).

Вы также можете использовать один метод, такой как set («Имя», «Абра»); или name = get («Имя»); получить доступ к любому полю в хэше, не записывая десятки сеттеров и геттеров ...

Я пришел к такому выводу после написания сотен экранов типа свойств, где данные просто извлекались из БД, представлялись на экране, модифицировались и затем отправлялись обратно в БД. В эти дни моя цель состоит в том, чтобы при этом я мог добавить новый элемент управления в процесс без единой строки кода - просто изменение метаданных.

Привязки к экрану и базе данных и даже проверки могут быть установлены как метаданные, и все становится намного проще ...

(Легче, если вы копируете и вставляете так же плохо, как и я ...)

...