Я разрабатываю свою собственную маленькую ООП-программу для симуляции вампиров, волков, людей и грузовиков и пытаюсь реализовать собственное ограниченное понимание интерфейсов.
( Я все еще абстрагируюсь здесь и не имею никакой реализации кода, так что это скорее вопрос ООП-дизайна ... Я думаю!)
Прав ли я в поиске «общего поведения» между этими классами и реализации их как интерфейсов ?
Например, вампиры и волки кусаются ... так должен ли я иметь интерфейс кусаться?
public class Vampire : Villain, IBite, IMove, IAttack
Аналогично для грузовиков ...
public class Truck : Vehicle, IMove
И для людей ...
public class Man : Human, IMove, IDead
Мое мышление прямо здесь? (Ценю твою помощь)
object-oriented
interfaces
user3396486
источник
источник
IEnumerable
,IEquatable
и т. Д.Ответы:
В общем, вы хотите иметь интерфейсы для общих характеристик вашего кластера.
Я частично согласен с @Robert Harvey в комментариях, который сказал, что обычно интерфейсы представляют более абстрактные особенности классов. Тем не менее, начиная с более конкретных примеров, я считаю хороший способ начать думать абстрактно.
Хотя ваш пример технически верен (т. Е. Да, вампиры и волки кусаются, так что вы можете иметь интерфейс для этого), существует вопрос актуальности. Каждый объект имеет тысячи характеристик (например, животные могут иметь мех, плавать, лазить по деревьям и т. Д.). Сделаете ли вы интерфейс для всех них? Очень менее вероятно.
Обычно вы хотите, чтобы интерфейсы для вещей, которые имеют смысл, были сгруппированы в приложении в целом. Например, если вы строите игру, вы можете иметь массив объектов IMove и обновить их положение. Если вы не хотите этого делать, иметь интерфейс IMove довольно бесполезно.
Дело в том, не переусердствуйте с инженером. Вам нужно подумать о том, как вы собираетесь использовать этот интерфейс, и 2 класса, имеющие общий метод, не являются достаточной причиной для создания интерфейса.
источник
IBite
это не особенно полезно, но вы можете захотеть,IAttack
чтобы вы могли работать над всеми вещами, которые делают атаки, илиIUpdate
чтобы вы могли запускать обновления для всего, илиIPhysicsEnabled
чтобы вы могли применять к ним физику и т. Д.Похоже, вы создаете кучу интерфейсов с одним методом . Это хорошо на первый взгляд, но имейте в виду, что интерфейсы не принадлежат классам, которые их реализуют. Они принадлежат клиентам, которые их используют. Клиенты решают, должно ли что-то быть чем-то, что может двигаться и атаковать.
Если у меня есть
Combat
класс сfight()
методом, то этот метод, вероятно, должен вызывать обаmove()
и один иattack()
тот же объект. Это настоятельно предполагает необходимостьICombatant
интерфейса, которыйfight()
может вызыватьmove()
иattack()
через. Это чище, чемfight()
взятьIAttack
объект и навести его на предметIMove
того, может ли он также двигаться.Это не значит, что вы не можете иметь
IMove
IAttack
интерфейсы. Я просто надеюсь, что вы не сделаете их без необходимости в клиенте. И наоборот, если ни одному клиенту не нужно заставлять объект двигаться и атаковать, тоICombatant
этом нет необходимости.Этот простой способ взглянуть на интерфейсы часто теряется, потому что людям нравится следовать примерам. Первые интерфейсы, с которыми мы сталкиваемся, находятся в библиотеках. К сожалению, библиотеки не имеют представления о своих клиентах. Таким образом, они могут только догадываться о потребностях своих клиентов. Не лучший пример для подражания.
источник
Подумайте, будет ли обычным иметь коллекции объектов с различными комбинациями способностей, и может ли код захотеть выполнить действие с теми элементами внутри коллекции, которые его поддерживают. . Если это так, и если будет разумное «поведение по умолчанию» для объектов, которые не имеют полезной поддержки для какого-либо действия, может быть полезно иметь интерфейсы, реализованные широким диапазоном классов, а не только теми, которые могут вести себя с пользой.
Например, предположим, что только несколько видов существ могут иметь Woozles, и каждый хочет, чтобы такие существа имели
NumerOfWoozles
свойство. Если бы такое свойство было в интерфейсе, который был реализован только существами, которые могут иметь Woozles, то код, который хотел бы найти общее количество Woozles, хранящегося в коллекции существ смешанных типов, должен был бы сказать что-то вроде:Однако, если бы WoozleCount был членом Creature / ICreature, хотя несколько подтипов переопределяли бы стандартную реализацию WoozleCount Creature, которая всегда возвращает ноль, код можно упростить до:
Хотя некоторые люди могут не согласиться с идеей, чтобы каждое Существо реализовало свойство WoozleCount, которое действительно полезно только для нескольких подтипов, свойство будет иметь смысл для всех типов, независимо от того, будет ли оно полезным для элементов, о которых известно, что они принадлежат к этим типам, и я бы расценил интерфейс «кухонной раковины» как нечто меньшее, чем запах кода, чем оператор trycast.
источник