基于某些条件创建不同的类型
本文关键字:类型 创建 于某些 条件 | 更新日期: 2023-09-27 18:24:09
我在一个应用程序中有一些代码,我现在并不是很兴奋。我创建了几个这样的类:
class Base
{
// base properties ...
}
class DerivedA : Base
{
}
class DerivedB : Base
{
}
我的应用程序中有一个方法,需要基于存储在数据库中的字符串属性创建其中一个对象(将来还会有更多对象)。这些对象中的每一个都从稍微不同的地方获取数据,但我现在这样做的方式只是一个很大的if块,而且它似乎不太可维护:
class BaseCreator
{
Base Create(string name)
{
if (name == "DerivedA" )
return CreateDerivedA();
else if(name == "DerivedB")
return CreateDerivedB();
}
}
有什么方法可以重构这些代码,使其更易于维护,并使其在未来更容易添加新类型?如果有什么不同的话,我会在我的应用程序中使用依赖项注入(Ninject)。
继承树一旦生长,就很难维护。如果你事先知道树会很大——认真考虑使用组合而不是继承。特别是如果您已经在使用DI框架,那么接口就是最好的选择。
我认为应该使用抽象工厂模式来解决这个问题。它提供了一个界面,用于创建相关或从属对象的族,而无需指定其具体类。http://www.dofactory.com/Patterns/PatternAbstract.aspx
或者只是工厂模式http://www.dotnetperls.com/factory
我会注意到您的if/else
或switch
结构并不是一件坏事。糟糕的是,当您多次将相同的if/else
或switch
表示为时
当你已经很好地解耦了代码,并且你正在对接口或抽象库而不是具体库进行编程时,要知道应用程序中的某处,某物知道如何创建你需要的特定具体实例。这可以是代码,可以是配置,可以是一些容器,等等。但必须存在。这个想法是让的东西存在一次
只要这是唯一存在的方法,你的方法就很好。这个类存在的原因是它创建了实现某些接口的具体实例。它改变的原因是添加(或删除)了一些其他的具体实现。
一般情况可以通过一些组合和使用规范模式来解决:
public class Base
{
public abstract bool IsSatisfiedBy(string name);
// base properties ...
}
public class DerivedA : Base
{
public override bool IsSatisfiedBy(string name)
{
return name == "DerivedA";
}
}
public class DerivedB : Base
{
public override bool IsSatisfiedBy(string name)
{
return name == "DerivedB";
}
}
public class BaseCreator
{
private readonly IEnumerable<Base> candidates;
public BaseCreator(IEnumerable<Base> candidates)
{
this.candidates = candidates;
}
public Base Create(string name)
{
return this.candidates.First(c => c.IsSatisfiedBy(name));
}
}
如果你真的必须使用字符串,你可以使用反射:
object GetInstance(string typeName)
{
Type.GetType(typeName).GetConstructor(Type.EmptyTypes).Invoke(new object[0]);
}
你也可以使用字典:
IDictionary<string, Func<object>> TypeMap = new Dictionary<string, Func<object>>()
{
{ "TypeA", () => new TypeA() },
{ "TypeB", () => new TypeB() },
{ "TypeC", () => new TypeC() },
};
object GetInstance(string typeName)
{
return TypeMap[typeName]();
}
对于其他登录此页面的用户,如果您没有使用字符串,请考虑使用泛型:
T CreateInstance<T>()
where T : new()
{
return new T();
}
这个问题没有一个通用的答案。抽象工厂可能是正确的,但这完全取决于这些实现之间的区别以及如何使用它们。
很可能您应该使用Template、Strategy、State或任何其他类似的模式。仔细研究它们,然后确定抽象工厂,并决定适合您特定场景的模式。