2010-05-13 4 views
5

Для моего проекта в семестре мы с моей командой должны сделать файл .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. Создать super ABC (абстрактный базовый класс), которые ВСЕ наследуют от

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

Что следует использовать? Или есть лучший способ?

ответ

6

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

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

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

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

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

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

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

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

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

0

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

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

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

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

1

Четвертым вариантом будет использование интерфейсов.

interface Enemy { 

    public void draw(); 

    . . . 

} 

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

0

Только маленький ответ из книги «Более эффективные C++» страница 271:

«Сделать базовые классы аннотацию, которые не в конце иерархии». Я слишком ленив, чтобы дать вам целую книгу, но автор указывает на некоторые веские причины.

+0

Существует также «Эффективная Java», которая более применима в этом случае. В нем говорится что-то подобное, но с вещами, более специфичными для Java - например, как 'equals()' не работает совершенно правильно при смешивании производных типов и базовых типов, если базовые классы не являются абстрактными. –

Смежные вопросы