Walk, Run и Swim кажутся реализациями, а не интерфейсами. Вы можете иметь интерфейс ILocomotion и позволить своему классу принять список реализаций ILocomotion.
Growl может быть реализацией чего-то вроде интерфейса IAbility. И конкретный монстр может иметь коллекцию реализаций IAbility.
Затем создайте пару интерфейсов, которые определяют, какую способность или локомоцию использовать: IMove, IAct, например.
public class AlienMonster : IMove, IAct
{
private List<IAbility> _abilities;
private List<ILocomotion> _locomotions;
public AlienMonster()
{
_abilities = new List<IAbility>() {new Growl()};
_locomotion = new List<ILocomotion>() {new Walk(), new Run(), new Swim()}
}
public void Move()
{
// implementation for the IMove interface
}
public void Act()
{
// implementation for the IAct interface
}
}
Составляя свой класс таким образом, вы избежите некоторой жесткости.
РЕДАКТИРОВАТЬ: добавил материал об IMove и IAct
РЕДАКТИРОВАТЬ: после некоторых комментариев
Добавляя IWalk, IRun и ISwim к монстру, вы говорите, что все, что может видеть объект, должно иметь возможность вызывать любой из методов, реализованных в любом из этих интерфейсов, и иметь его смысл. Далее, чтобы решить, какой из трех интерфейсов следует использовать, вы должны передать весь объект. Одним из огромных преимуществ использования интерфейса является то, что вы можете ссылаться на него по этому интерфейсу.
void SomeFunction(IWalk alienMonster) {...}
Приведенная выше функция будет принимать все, что реализует IWalk, но если есть варианты SomeFunction для IRun, ISwim и т. Д., Вам нужно написать совершенно новую функцию для каждого из них или передать объект AlienMonster целиком. Если вы передаете объект, то эта функция может вызывать любой и все интерфейсы на нем. Это также означает, что эта функция должна запросить объект AlienMonster, чтобы увидеть его возможности, а затем решить, какие из них использовать. Все это приводит к тому, что внешние функции становятся более функциональными, и их следует хранить внутри класса. Поскольку вы все это экстернализуете, и между IWalk, IRun, ISwim нет общего, поэтому некоторые функции могут невинно вызывать все три интерфейса, и ваш монстр может одновременно бегать-ходить-плыть. Кроме того, поскольку вы захотите иметь возможность вызывать IWalk, IRun, ISwim для некоторых классов, все классы должны будут в основном реализовывать все три интерфейса, и в итоге вы создадите стратегию, подобную CannotSwim, для удовлетворения требований интерфейса для ISwim, когда монстр не умею плавать. В противном случае вы можете попытаться вызвать интерфейс, который не реализован на монстре. В конце вы фактически ухудшаете код для дополнительных интерфейсов, IMO.