Неплохая ли политика, чтобы иметь много «рабочих» классов (таких как классы стратегии), что только одно?Взрыв классов стратегии и «действия»
Предположим, я хочу создать класс монстров. Вместо того, чтобы просто определять все, что я хочу о монстре в одном классе, я попытаюсь определить, каковы его основные функции, поэтому я могу определить их в интерфейсах. Это позволит:
- Уплотните класс, если я захочу. Позже другие пользователи могут просто создать новый класс и по-прежнему иметь полиморфизм с помощью интерфейсов, которые я определил. Мне не нужно беспокоиться о том, как люди (или я) могут захотеть изменить/добавить функции в базовый класс в будущем. Все классы наследуют от Object и реализуют наследование через интерфейсы, а не от материнских классов.
- Повторное использование стратегий, которые я использую с этим монстром для других участников моего игрового мира.
Con: Эта модель жесткая. Иногда мы хотели бы определить то, чего нелегко добиться, просто пытаясь собрать эти «строительные блоки».
public class AlienMonster : IWalk, IRun, ISwim, IGrowl {
IWalkStrategy _walkStrategy;
IRunStrategy _runStrategy;
ISwimStrategy _swimStrategy;
IGrowlStrategy _growlStrategy;
public Monster() {
_walkStrategy = new FourFootWalkStrategy();
...etc
}
public void Walk() { _walkStrategy.Walk(); }
...etc
}
Моя идея была бы рядом, чтобы сделать ряд различных стратегий, которые могут быть использованы различными монстрами. С другой стороны, некоторые из них могут также использоваться для совершенно разных целей (т. Е. Я мог бы иметь танк, который также «плавает»). Единственная проблема, которую я вижу при таком подходе, состоит в том, что это может привести к взрыву чистых классов «методов», т. Е. Классов стратегии, которые имеют единственную цель, делают то или иное действие. С другой стороны, такая «модульность» позволяла бы использовать многократное использование стратагий, иногда даже в совершенно разных контекстах.
Каково ваше мнение по этому вопросу? Является ли это обоснованным аргументом? Является ли это чрезмерной инженерией?
Кроме того, если предположить, что мы сделаем соответствующие корректировки в примере, который я дал выше, было бы лучше, чтобы определить IWalk как:
interface IWalk {
void Walk();
}
или
interface IWalk {
IWalkStrategy WalkStrategy { get; set; } //or something that ressembles this
}
в том, что делать это я не нужно было бы определять методы самого монстра, у меня бы просто были публичные геттеры для IWalkStrategy (это, похоже, противоречит идее, что вы должны инкапсулировать все столько, сколько сможете!) Почему?
Благодаря
Еще одна приятная вещь в этом заключается в том, что, когда вы хотите перейти от A к B, вы можете просто перебрать свой список интерфейсов локомоции и спросить каждую стоимость вместо жесткого кодирования «получить стоимость ходьбы, получить стоимость прогона получить стоимость плавания, получить стоимость вылета, получить телепортную стоимость, ... »и нести технический долг, чтобы сохранить этот список в соответствии с новыми типами локомотивов. –
Не могли бы вы объяснить, почему Walk, Run и Swim вам больше нравятся реализации, чем интерфейсы? Должна ли вообще модель интерфейса что-то определенному классу «делать»? ISwim будет означать, что мой монстр (или танк, или какой бы класс, который я пытаюсь реализовать) не мог плавать. Тогда я мог бы реализовать несколько различных классов стратегий (например), таких как SwimInWater SwimInAcid и т. Д. Что мне здесь не хватает? –
Позвольте мне перефразировать «Интерфейсы не описывают, что-то может сделать как таковое». Рекомендуется использовать интерфейсы логичным и последовательным образом. Использование ILocomotion to Growl было бы плохим выбором. Но ходить, плавать, бегать, летать, телепортироваться и т. Д. - все это просто формы движения. Абстрагируя их на интерфейс движения, вы можете значительно упростить свой код. Вы можете иметь 100 реализаций ILocomotion и быть лучше, чем 20 IWalk, 20 IRun, 20 ISwim, 20 ISkip, 2 ITeleport, 18 IJump-реализаций. Если что-то не соответствует интерфейсу ILocomotion, создайте новый интерфейс. – Felan