基于某些条件创建不同的类型

本文关键字:类型 创建 于某些 条件 | 更新日期: 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/elseswitch结构并不是一件坏事。糟糕的是,当您多次将相同的if/elseswitch表示为

当你已经很好地解耦了代码,并且你正在对接口或抽象库而不是具体库进行编程时,要知道应用程序中的某处某物知道如何创建你需要的特定具体实例。这可以是代码,可以是配置,可以是一些容器,等等。但必须存在。这个想法是让的东西存在一次

只要这是唯一存在的方法,你的方法就很好。这个类存在的原因是它创建了实现某些接口的具体实例。它改变的原因是添加(或删除)了一些其他的具体实现。

一般情况可以通过一些组合和使用规范模式来解决:

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或任何其他类似的模式。仔细研究它们,然后确定抽象工厂,并决定适合您特定场景的模式。