C# class 子工厂 classes

C# class factory with subclasses

我正在努力创建一个工厂模式,其中不是工厂,但 classes 确定需要使用哪个 class 来创建对象。为了使它比普通工厂模式更复杂,classes 通常需要创建一个 subclass 的实例。

我想做类似的事情:

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

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

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

您可以考虑将生物体工厂与生物体数据分开 类。这意味着您将工厂与数据 类 耦合,但不会将数据 类 相互耦合(除了通过继承)。

例如:

//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.
    }
}

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

interface IOrganismSubFactory
{
    Organism Create(Observation observation);
}

例如一个 "sub" 工厂可能看起来像这样

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

然后您可以使用这个工厂来创建(我们尝试创建)实例

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

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

另一个优势是您可以使用依赖注入库来包装此逻辑,然后使您能够使用 IoC。基本上这意味着子工厂可以声明对其他 class 的依赖关系,这些 class 会自动注入到这些子工厂中。

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