Вы можете создать интерфейс для фабрики, который создает исполнителя команд для данного типа команд. Также добавьте функцию для регистрации фабрики в вашей библиотеке. Когда вам нужно выполнить команду, вы можете дать зарегистрированной фабрике команду и получить объект исполнителя. Если я правильно понял вашу проблему, этот код живет на стороне библиотеки.
Теперь со стороны вашего приложения вы можете создать реализацию фабрики, зарегистрировать все известные типы команд в классах, которые могут их выполнять, и наконец зарегистрировать эту фабрику в библиотеке.
Есть довольно много разных способов сделать это. Я добавлю, что вы не захотите добавлять void Execute()
к SceneInfo
, KeyFrameInfo
или IKeyFrameCommandInfo
- в конце концов, это классы информации. Итак, давайте создадим класс SceneRunner
:
public class SceneRunner
{
public ExecuteScene(SceneInfo scene) {
// loop over scene.KeyFrames and keyFrames.Commands, and execute
}
}
Поскольку мы не знаем, как выполнять эти команды, давайте создадим фабрику, которая позволит нам получить класс, который знает, как это сделать:
public interface IKeyFrameCommandFactory
{
IKeyFrameCommand GetCommand(IKeyFrameCommandInfo info);
}
И добавьте заводской интерфейс и механизм регистрации для бегуна. Поскольку сторона приложения, вероятно, не захочет иметь дело с экземплярами этого, давайте сделаем оба статических:
public class SceneRunner
{
static public RegisterFactory(IKeyFrameCommandFactory factory)
{
this.factory = factory;
}
static private IKeyFrameCommandFactory factory = null;
}
Пока все хорошо. Теперь время для заводского кода (на стороне клиента библиотеки). Это очень похоже на то, что Дэрил предложил (вы можете использовать его дословно, просто добавив спецификацию интерфейса):
public void KeyCommandFactory: IKeyFrameCommandFactory
{
private static Map<Type, Type> mappings;
public IKeyCommand GetKeyCommand(IKeyCommandInfo info)
{
Type infoType = info.GetType();
return Activator.CreateInstance(mappings[infoType], info);
}
}
Если вам не нравится размышлять, вы можете реализовать Prototype Pattern в своих командах и использовать IDictionary<Type, IPrototype> mappings;
в качестве карты и mappings[infoType].Clone()
, чтобы получить новый экземпляр команда.
Теперь осталось две вещи: связать информационные классы с классами команд и зарегистрировать вашу фабрику. Оба должны быть довольно очевидными.
Для ассоциаций вы можете либо добавить RegisterCommand(Type infoType, IPrototype command)
к своей фабрике и добавить ассоциации к точке входа вашей программы, либо преобразовать их в статический метод и вызвать этот метод из точки входа программы. Вы даже можете создать атрибут для указания информационного класса командного класса, анализа вашей сборки и автоматического добавления ассоциаций.
И, наконец, зарегистрируйте свою фабрику в SceneRunner, позвонив по номеру SceneRunner.RegisterFactory(new KeyCommandFactory())
.