在下面的代码中,我希望根据另一个类的类型返回派生类,这是一种更优雅的方式。
if (option_ is Rectangle)
{
modelInputs = new Foo();
}
else if (option_ is Circle)
{
modelInputs = new Bar();
}
else if (option_ is Triangle)
{
modelInputs = new Bar2();
}
答案 0 :(得分:8)
让Rectangle,Circle和Triangle实现IHasModelInput:
interface IHasModelInput
{
IModelInput GetModelInput();
}
然后你可以做
IModelInput modelInputs = option_.GetModelInput();
答案 1 :(得分:3)
我的观点:你的“不雅”方式很好。它简单易读,可以完成任务。
让Rectangle,Circle和Triangle通过 IHasModelInput 实现必要的工厂函数会起作用,但它有一个设计成本:你现在已经将这组类与IModelInput类集合在一起( Foo,Bar和Bar2)。他们可能在两个完全不同的图书馆,也许他们不应该彼此了解。
下面是一个更复杂的方法。它为您提供了在运行时配置工厂逻辑的优势。
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;
}
然后问一个问题:你想读哪一个?
答案 2 :(得分:1)
您可以将输入和输出放在Hashtable中,或者存储在您创建的每个类中创建每个类的类型,然后使用Activator.CreateInstance来完成工厂':
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中运行的一种非常酷的方式。儿子,享受并使用我明智地给你的力量。
答案 3 :(得分:0)
如果类型允许,您可以将类型与“option_”相关联,然后只创建它的实例。
答案 4 :(得分:0)
当我想在运行时将字符串转换为类型时,我通常使用这样的工厂方法,我使用将字符串映射到Type的Dictionary。
来自最近的一个项目:
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;
}
}
}