根据某些条件创建不同的类型

时间:2012-02-10 20:52:20

标签: c# design-patterns inversion-of-control

我在应用程序中有一些代码,我现在并不是很兴奋。我创建了几个类:

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),如果这有任何区别。

6 个答案:

答案 0 :(得分:1)

继承树一旦生长就很难维护。如果你事先知道树会很大 - 认真考虑使用组合而不是继承。特别是如果您已经在使用DI框架,那么接口就是最佳选择。

答案 1 :(得分:1)

如果你真的必须使用字符串,你可以使用反射:

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();
}

答案 2 :(得分:1)

我认为你应该使用解决这个问题的抽象工厂模式。 它提供了一个接口,用于创建相关或从属对象的族,而无需指定其具体类。 http://www.dofactory.com/Patterns/PatternAbstract.aspx

或者只是工厂模式 http://www.dotnetperls.com/factory

答案 3 :(得分:1)

我会注意到您的if/elseswitch结构不是坏事。不好的是,您多次使用相同的if/elseswitch表达

当你很好地解耦你的代码而你正在编程接口或抽象基础而不是具体的时候,知道应用程序中的某处某些东西知道如何创建您需要的特定具体实例。这可以是代码,它可以是配置,它可以是一些容器等。但是某些东西必须存在。我们的想法是让某些东西存在一次。

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

答案 4 :(得分:1)

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

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));
    }
}

答案 5 :(得分:0)

这个问题没有一般性答案。抽象工厂可能是正确的,但这完全取决于这些实现与您如何使用它们之间的区别。

很可能你应该使用Template,Strategy,State或任何其他类似的模式。查看它们,绝对是抽象工厂,并决定适合您特定场景的模式。