Абстрактный базовый класс или класс?

Для моего проекта семестра моя команда и я, как предполагается, делаем .jar файл (библиотека, не выполнимая), который содержит платформу разработки игр, и продемонстрируйте понятие ООП. Ее воображаемое, чтобы быть ПЛАТФОРМОЙ и другой командой, как предполагается, использует нашу платформу и наоборот. Таким образом, я хочу знать, как мы должны запустить. Мы думали о нескольких подходах:
1. Запустите с простого класса

public class Enemy {
    public Enemy(int x, int y, int health, int attack, ...) {
        ...
    }
    ...
}
public class UserDefinedClass extends Enemy {
    ...
}

2. Запустите с абстрактного класса, что пользовательские враги должны наследовать абстрактных участников

public abstract class Enemy {
    public Enemy(int x, int y, int health, int attack, ...) {
        ...
    }
    public abstract void draw();
    public abstract void destroy();
    ...
}
public class UserDefinedClass extends Enemy {
    ...
    public void draw() {
        ...
    }
    public void destroy() {
        ...
    }
}

3. Создайте супер ABC (Абстрактный базовый класс), которому ВСЕ наследовались

public abstract class VectorEntity {
    ...
}
public abstract class Enemy extends VectorEntity {
    ...
}
public class Player extends VectorEntity {
    ...
}
public class UserDefinedClass extends Enemy {
    ...
}

Который я должен использовать? Или есть ли лучший путь?

5
задан Mohit Deshpande 13 May 2010 в 23:45
поделиться

4 ответа

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

  1. Собираются ли они на самом деле создать экземпляр Enemy, или все враги действительно должны быть производного типа? Если вы на самом деле не собираетесь создавать экземпляры Enemies, а не производных типов, то, скорее всего, это должен быть интерфейс или абстрактный класс.

  2. Если вы хотите обеспечить реальное поведение в своем базовом классе, то, очевидно, это должен быть класс, а не интерфейс.

  3. Методы, которые должны присутствовать в API, но не имеют смысла предоставлять какие-либо реализации, должны быть абстрактными.

  4. Методы, для которых имеет смысл иметь реализации в базовом классе, должны иметь реализации в базовом классе. И если их отменять не имеет смысла, сделайте их окончательными.

  5. Создание классов, совместно использующих общий базовый класс, действительно имеет смысл только в том случае, если они действительно разделяют поведение или вам нужно иметь возможность обрабатывать их все одинаково где-то в вашем коде. Если они на самом деле не так похожи, то, вероятно, им не следует разделять базовый класс. Например, если предполагается, что и Enemy, и Player могут отображаться, может иметь смысл иметь общий базовый класс, который обрабатывает их функции отображения. Но если бы Enemy был чем-то, что можно было отображать, а Player был бы более абстрактным понятием - как контроллер игры - и не отображался бы, то, вероятно, им не было бы смысла делить базовый класс. В общем, при построении классов лучше предпочесть композицию, а не наследование, поэтому, если рассматриваемые классы на самом деле не будут совместно использовать поведение и на самом деле не имеют отношения «is-a» с общим базовым классом, тогда они не должны иметь общий базовый класс.

  6. Предпочитайте, чтобы ваши базовые классы совместно использовали только методы, а не данные. Другими словами, в дереве наследования лучше всего, чтобы экземпляры создавались только для листьев. Существуют различные вещи, такие как equals () , которые не работают, когда у вас есть базовые классы с фактическими данными в них. Это не значит, что вы не можете этого сделать - люди делают это все время, - но это может вызвать проблемы, и лучше избегать этого, если в этом нет необходимости.

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

Я уверен, что мог бы придумать больше, но, не зная вашего проекта, он наверняка будет довольно общим. Из 3 вариантов, которые вы указали, я бы, вероятно, выбрал 2. 3 кажется, что вы, вероятно, создаете базовый класс для несвязанных классов, а 1 приведет к созданию экземпляра Enemy, который вам, вероятно, не нужен и определенно сделал бы так, чтобы экземпляры были созданы не только для листьев в иерархии наследования. Вероятно, вы по-прежнему останетесь с данными в базовых классах с 2, но вы, скорее всего, переопределите только абстрактные методы, и у вас будет меньше проблем с измененным поведением в производных классах.

6
ответ дан 14 December 2019 в 08:44
поделиться

Четвертый вариант - использовать интерфейсы.

interface Enemy {

    public void draw();

    . . .

}

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

1
ответ дан 14 December 2019 в 08:44
поделиться

Небольшой ответ из книги "Более эффективный с++" стр. 271:

"Делайте базовые классы абстрактными, которые не находятся в конце иерархии". Мне лень читать всю главу, но автор перечисляет несколько веских причин для этого.

0
ответ дан 14 December 2019 в 08:44
поделиться

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

Итак, если это делаю я:

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

Если только методы являются общими для классов, можно также использовать interfaces. Однако я всегда нахожу, что рано или поздно я вижу, что классы, реализующий interface, имеют одинаковые поля private. На этом этапе я преобразую interface в абстрактный класс, который содержит эти закрытые поля (чтобы сэкономить на строках кода, если не на чем-то другом).

0
ответ дан 14 December 2019 в 08:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: