Наследование интерфейса - это хорошо? - PullRequest
2 голосов
/ 19 мая 2009

Я только что использовал его впервые - рассмотрим:

IGameObject
    void Update()

IDrawableGameObject : IGameObject
    void Draw()

У меня был класс уровня, который использовал DrawableGameObjects - вместо этого я переключил его на IDrawableGameObject, чтобы уменьшить сцепление и помощь в TDD.

Однако я, конечно, теряю способность вызывать Update (..) без приведения - чтобы обойти это, я использовал наследование. Я никогда раньше не использовал наследование на основе интерфейса - и я действительно не нашел в этом необходимости, кроме как в этом случае.

Я действительно не хотел каждый раз приводить в своем методе обновления, так как он вызывается до 60 раз в секунду, с другой стороны, мог бы сработать foreach (..), который использовал бы IGameObject.

Любой совет?

Редактировать

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

Спасибо

Ответы [ 5 ]

5 голосов
/ 19 мая 2009

Я знаю, что интерфейсы должны быть только горстка членов большая

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

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

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

// just a silly example that only uses members of the target type
public static void DrawComplete(this IDrawableGameObject obj, Canvas canvas) {
   obj.Draw(canvas);
   foreach(var child in obj.Children.OfType<IDrawableGameObject>()) {
       child.DrawComplete(canvas);
   }
}

тогда все вызывающие получают метод DrawComplete без необходимости повторения всеми реализациями.

3 голосов
/ 19 мая 2009

Наследование, основанное на интерфейсе, на самом деле ничем не отличается от обычного наследования с точки зрения «если ты это сделаешь». Он по-прежнему выражает отношения «есть» между двумя типами. Таким образом, в этом случае, если IDrawableGameObject действительно является IGameObject в том виде, в каком он есть, наследование имеет смысл.

0 голосов
/ 19 мая 2009

Как говорит JaredPar, в наследовании интерфейса нет ничего плохого; пока один является логическим базовым типом другого, это просто деталь реализации. Если вы не можете просто ответить на этот вопрос (всегда ли верно, что IDrawableGameObject является IGameObject?), Возможно, ваша модель нуждается в некотором переосмыслении. Например, может иметь смысл разделить созданную вами иерархию на два независимых интерфейса IUpdateable и IDrawable; ничто не мешает одному классу реализовать оба интерфейса.

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

0 голосов
/ 19 мая 2009

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

0 голосов
/ 19 мая 2009

Следует обратить внимание на то, что наследование интерфейса, применяемое таким образом, заключается в том, что дополнения к корневому интерфейсу могут создать большие объемы работы, чтобы сделать реализации интерфейса совместимыми с новым изменением (в большом проекте). Это также может затруднить принятие правильного решения относительно того, к какому интерфейсу принадлежит метод, если у вас есть несколько уровней наследования интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...