Фабрика основана на Typeof или является
Вопрос
Какой более элегантный способ иметь приведенный ниже код, где я хочу вернуть производный класс, основанный на типе другого класса.
if (option_ is Rectangle)
{
modelInputs = new Foo();
}
else if (option_ is Circle)
{
modelInputs = new Bar();
}
else if (option_ is Triangle)
{
modelInputs = new Bar2();
}
Решение
Rectangle, Circle и Triangle должны реализовывать IHasModelInput:
interface IHasModelInput
{
IModelInput GetModelInput();
}
тогда вы можете сделать
IModelInput modelInputs = option_.GetModelInput();
Другие советы
Мое мнение: ваш " неэлегантный " путь в порядке. Это просто, читабельно и делает свою работу.
Если бы Rectangle, Circle и Triangle реализовали необходимую фабричную функцию через IHasModelInput , это сработало бы, но это стоило разработки: теперь вы связали этот набор классов с набором классов IModelInput ( Фу, Бар и Бар2). Они могут находиться в двух совершенно разных библиотеках, и, возможно, они не должны знать друг о друге.
Более сложный метод приведен ниже. Это дает вам преимущество в том, что вы можете настроить свою фабричную логику во время выполнения. Р>
public static class FactoryMethod<T> where T : IModelInput, new()
{
public static IModelInput Create()
{
return new T();
}
}
delegate IModelInput ModelInputCreateFunction();
IModelInput CreateIModelInput(object item)
{
Dictionary<Type, ModelInputCreateFunction> factory = new Dictionary<Type, ModelInputCreateFunction>();
factory.Add(typeof(Rectangle), FactoryMethod<Foo>.Create);
factory.Add(typeof(Circle), FactoryMethod<Bar>.Create);
// Add more type mappings here
IModelInput modelInput;
foreach (Type t in factory.Keys)
{
if ( item.GetType().IsSubclassOf(t) || item.GetType().Equals(t))
{
modelInput = factory[t].Invoke();
break;
}
}
return modelInput;
}
Но тогда задайте вопрос: что бы вы предпочли прочитать?
Вы можете поместить входные и выходные данные в Hashtable или сохранить типы, которые создают каждый класс внутри каждого из создаваемых вами классов, а затем использовать Activator.CreateInstance для выполнения factoryin ':
Hashtable ht = new Hashtable();
ht.Add(typeof(Rectangle), typeof(Bar));
ht.Add(typeof(Square), typeof(Bar2));
modelInputs = Activator.CreateInstance(ht[option.GetType()]);
В любом случае Activator.CreateInstance - это довольно крутой способ заставить фабрики работать в .NET. Наслаждайся и используй силу, которую я дал тебе мудро, сынок.
Вы можете связать тип с " option_ " ;, если это позволяет, а затем просто создать его экземпляр.
Обычно я использую фабричный метод, подобный этому, когда я хочу преобразовать строку в тип во время выполнения, я использую словарь, который отображает строку в тип.
Как из недавнего проекта:
public class TaskFactory
{
private Dictionary<String, Type> _taskTypes = new Dictionary<String, Type>();
public TaskFactory()
{
// Preload the Task Types into a dictionary so we can look them up later
foreach (Type type in typeof(TaskFactory).Assembly.GetTypes())
{
if (type.IsSubclassOf(typeof(CCTask)))
{
_taskTypes[type.Name.ToLower()] = type;
}
}
}
public CCTask CreateTask(XmlElement task)
{
if (task != null)
{
string taskName = task.Name;
taskName = taskName.ToLower() + "task";
// If the Type information is in our Dictionary, instantiate a new instance of that task
Type taskType;
if (_taskTypes.TryGetValue(taskName, out taskType))
{
return (CCTask)Activator.CreateInstance(taskType, task);
}
else
{
throw new ArgumentException("Unrecognized Task:" + task.Name);
}
}
else
{
return null;
}
}
}