带有子类的C#类工厂

时间:2018-04-01 22:06:19

标签: c# class oop inheritance factory

我努力创建一个工厂模式,而不是工厂,但是类确定需要使用哪个类来创建对象。为了使它比正常的工厂模式更复杂,类通常需要创建一个子类的实例。

我想做类似的事情:

class Observation {
  public int NumLegs;
  public bool HasWings;
  public NumChromosomes;
  //  etc. 
}

class Organism {
  public static Organism CreateByObservation(Observation obs) {
    if (obs.numLegs == 4) return new Mammal.CreateByObservation(obs);
    else if (obs.HasWings) return new Bird.CreateByObservation(obs);
    // etc.
  }
}

class Mammal: Organism {
  public static override Mammal CreateByObservation(Observation obs) {
    if (obs.NibblesALot) return new Rodent.CreateByObservation(obs);
    else if (obs.Whinnies) return new Horse();
    // etc.
  }
}

class Rodent: Mammal {
  public static override Rodent CreateByObservation(Observation obs) {
    if (obs.Color == Colors.GRAY) return new Mouse();
    else // ... you get the idea
  }
}

// usage:
var myobservation = new Observation() { ... };
var myorganism = new Organism.CreateByObservation(myobservation);
tbName = myorganism.GetName();

由于显而易见的原因,我想将确定代码封装在子类中(Organism应该对啮齿动物一无所知),但由于在C#中不允许覆盖静态方法,因此我无法使用上述代码。

处理此问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

您可以考虑将您的生物工厂与您的生物数据类别分开。这意味着您将工厂与数据类耦合,但您不会将数据类彼此耦合(除了继承)。

例如:

//Organism objects

class Organism { ... } 
class Mammal : Organism { ... } 
class Rodent : Mammal { ... } 

//Factory

class OrganismFactory 
{
    public static Organism CreateByObservation(Observation obs) 
    {
        if (obs.numLegs == 4) return new Mammal.CreateByObservation(obs);
        else if (obs.HasWings) return new Bird.CreateByObservation(obs);
        // etc.
    }
}

答案 1 :(得分:2)

如果您的应用程序增长,您可以查看程序集扫描。基本上你可以创建实现这个接口的各种类,每个可能的Organism子类型一个单独的类

interface IOrganismSubFactory
{
    Organism Create(Observation observation);
}

例如,一个“子”工厂可能看起来像这样

class MammalFactory : IOrganismSubFactory
{
    public Organism Create(Observation observation)
    {
        if (observation.NumLegs != 4) return null;

        return new Mammal(obs);
    }
}

现在要把事情联系在一起,你扫描装配并获得所有可能的子工厂并在工厂中将它们统一起来

class OrganismFactory
{
    IOrganismSubFactory[] _subFactories;

    public OrganismFactory()
    {
        _subFactories = Assembly.GetCallingAssembly().GetTypes()
                                .Where(t => typeof(IOrganismSubFactory).IsAssignableFrom(t))
                                .Select(t => (IOrganismSubFactory)Activator.CreateInstance(t))
                                .ToArray();
    }

    public Organism Create(Observation observation)
    {
        return _subFactories.Select(factory => factory.Create(observation)).FirstOrDefault(instance => instance != null);
    }
}

然后,您可以使用此Factory创建(尝试创建)实例

var factory = new OrganismFactory();
var organism = factory.Create(observation);
// organism is null if no factory was found

这可能是一个好主意的原因是您的代码明确分开,但您必须记住为每个可能的类创建工厂。

另一个优点是您可以使用依赖注入库来包装此逻辑,然后使您能够使用IoC。基本上这意味着子实例可以声明对自动注入这些子实例的其他类的依赖。

这可能超出了您当前问题的范围,但仍然有趣了解