Я считаю, что вы должны использовать интерфейс и убедиться, что все ваши методы "DrawShadow" соответствуют этому интерфейсу. Таким образом, вы можете создать список заклинателей теней, которые соответствуют интерфейсу.
Пока объект реализует этот интерфейс, вы знаете, что можете сказать ему нарисовать тень. Фактический рисунок тени будет оставлен на усмотрение самого объекта при условии правильного устройства для рисования.
Например:
class Program
{
public static void Main()
{
var shadowCasters = new List<ICastShadow>();
shadowCasters.Add(new Car());
shadowCasters.Add(new Plane());
var castShadows = true;
if (castShadows)
{
foreach (var caster in shadowCasters)
{
caster.DrawShadow(null);
}
}
Console.Read();
}
public class Car : ICastShadow
{
public void DrawShadow(object device)
{
Console.WriteLine("Car Shadow!");
}
}
public class Plane : ICastShadow
{
public void DrawShadow(object device)
{
Console.WriteLine("Plane Shadow!");
}
}
public interface IShadowCaster
{
void DrawShadow(object device);
}
}
Когда вам нужно проверить, способен ли ваш объект отбрасывать тени, вы можете использовать ключевое слово "is" ...
if(myTrain is ICastShadow)
{
shadowCasters.Add(myTrain);
}
Надеюсь, это поможет! :)
редактировать
Причина, по которой вы не захотите использовать наследование, заключается в том, что все ваши игровые объекты рисуют тени по-разному, и если некоторые из ваших производных классов не отбрасывают тени. Например:
У вас есть BrickBuilding и GlassBuilding. Кирпичное здание должно отбрасывать тень, а стеклянное здание не должно. Они оба наследуются от Building, который наследуется от ShadowCaster. Даже если все ваши классы отбрасывания теней рисуют тени одинаково, вам все равно нужно сделать методы ShadowCaster виртуальными, чтобы GlassBuilding мог их переопределить и ничего не делать при вызове этого метода.
Используя композицию вместо наследования (т.е. используйте интерфейс), вы сможете составить метод рисования теней только на тех классах, которые фактически отбрасывают тени, и у вас на один класс меньше в вашей иерархии (что делает ремонтопригодность легким).
Так что же происходит, когда вы используете интерфейс и начинаете повторять одну и ту же логику снова и снова, потому что все ваши классы рисования теней рисуют тени одинаково? Очевидно, это не лучшая идея. Но если все они рисуют тени одинаково, вы можете использовать другой класс для рисования теней для их. Затем идет класс "ShadowCaster".
Реализация теневого рисования для каждого объекта затем вызывала бы метод этого ShadowCaster, чтобы нарисовать тень для него. Это позволяет каждому объекту параметр рисования теней по-своему, но также предоставляет способ для каждого объекта использовать реализацию рисования теней по умолчанию. Он также предоставляет возможность легко добавлять и удалять возможность рисовать тени для определенных объектов (просто не позволяйте объектам реализовывать интерфейс ICastShadow).
Чтобы сделать еще один шаг вперед, вы можете рассматривать отбрасывание теней как другой метод рисования и создавать обобщенный интерфейс для рисования теней / частиц / отражений / трон-свечения и т. Д., А также создавать различные «модули», которые выполняют эти разные функции. вещи. Вместо того, чтобы ваш класс реализовывал ICastShadows, он должен реализовывать «IDrawModules», а затем давать каждому классу правильные модули во время выполнения.
Другими словами, вы можете добавить модуль «CastShadow» в BrickBuilding и добавить модуль «Reflect» в GlassBuilding, и ваш код будет вызывать «DrawModules» для обоих объектов (из интерфейса IDrawModules).
Хорошо, это становится действительно очень долго, Надеюсь, это поможет, и это не слишком запутанно.
Я бы посоветовал прочесть первые пару глав «Head First Design Patterns». Это книга на Java, но принципы для большинства языков одинаковы.