如何使用枚举解析类类型

log*_*eks 5 c# oop design-patterns

我的项目中有一组课程(遵循策略模式).在main函数中,我从服务器接收枚举值,并根据该值创建基类类型的对象.

我正在使用switch/case语句来实现这一点.我在某处读到,无论何时添加新类,Open/Closed原则都不允许打开函数来添加新的case语句.

我正在考虑使用Activator.CreateInstance().有没有任何缺点.

有没有其他方法可以从枚举类型创建对象?

添加下面的示例,即使它不是一个完整的战略模式

abstract public class Mammal
{
   public abstract void MakeSound()
}

class Cat:Mammal
{      
    public override  void MakeSound()
    {
        Console.WriteLine("Meow");        
    }    
}

class Dog:Mammal
{

    public override void MakeSound()
    {
         Console.WriteLine("Bow");        
    }    
}

Main()
{

    MammalTypes mammalType = RecieveValueFromServer();
    Mammal mammalBase
    switch(mammalType) // need to make this dynamic depending upon Enum type
    {
        case MammalTypes.Cat:mammalBase = new Cat()
                             break;
        case MammalTypes.Dog:mammalBase = new Dog()
                             break;            
    }

    mammalBase.MakeSound()
}
Run Code Online (Sandbox Code Playgroud)

Cri*_*scu 5

实现真正的OCP的一种方法可能是以下方法:

定义一个抽象方法,Is以强制哺乳动物的每个具体子类型指定它是否适合给定的枚举值:

abstract public class Mammal
{
    public abstract void MakeSound();

    public abstract bool Is(MammalTypes mammalType);
}
Run Code Online (Sandbox Code Playgroud)

子类中Is的实现如下所示:

class Cat : Mammal
{
    // other specific members

    public override bool Is(MammalTypes mammalType)
    {
        return mammalType == MammalTypes.Cat;
    }
}

class Dog : Mammal
{
    // other specific members

    public override bool Is(MammalTypes mammalType)
    {
        return mammalType == MammalTypes.Dog;
    }
}
Run Code Online (Sandbox Code Playgroud)

完成此操作后,我们现在可以创建一个MammalFactory类,当给定Mammal枚举值扫描可用的类时,当找到匹配项时,它将返回该类的实例:

public class MammalFactory
{
    private readonly IEnumerable<Type> _mammalTypes;

    public MammalFactory()
    {
        var currentAssembly = Assembly.GetExecutingAssembly();

        _mammalTypes = currentAssembly.GetTypes()
            .Where(t => typeof(Mammal).IsAssignableFrom(t) && !t.IsAbstract);
    }

    public Mammal Create(MammalTypes mammalType)
    {
        return _mammalTypes
            .Select(type => CreateSpecific(type, mammalType))
            .First(mammal => mammal != null);
    }

    public Mammal CreateSpecific(Type type, MammalTypes mammalEnumType)
    {
        var mammalInstance = (Mammal)Activator.CreateInstance(type);

        return mammalInstance.Is(mammalEnumType) ? mammalInstance : null;
    }
}
Run Code Online (Sandbox Code Playgroud)

最终用法将如下所示:

var mammalFactory = new MammalFactory();

var guessWhatMammal = mammalFactory.Create(MammalTypes.Cat);
Run Code Online (Sandbox Code Playgroud)

这完全符合OCP。只需创建一个新的Mammal类即可自动将其连接并准备在应用程序中使用。(除了枚举本身,无需修改应用程序中的任何其他内容)

这种方法存在一些问题:

  • 它只扫描当前执行的程序集中的哺乳动物类型
  • 每次需要测试该类型是否合适时,都必须创建一个哺乳动物实例

尽管可以解决这些问题,但仍然存在一个问题:复杂性

这很复杂,因为:

  • 我们将所需的代码量增加了一倍
  • 自动接线可能会使刚接触该项目的人们感到困惑

我认为结论是:设计模式不是严格的规则。仅仅为了符合给定的设计而做某事是不值得的。相反,我们必须务实,并在模式一致性和有用性/简单性/可读性之间找到完美的平衡。这在很大程度上取决于我们试图解决的问题,在许多情况下,很可能就是switch您在问题中提出的陈述。


Chr*_*dal 1

您可以使用从枚举类型到函数的字典。这些函数创建您的策略对象:

public delegate Strategy StrategyFactory();
var strategyFactories = new Dictionary<MyEnum, StrategyFactory>();
Run Code Online (Sandbox Code Playgroud)

该字典用于根据枚举值创建对象:

var newStategy = strategyFactories[myEnumValue]();
Run Code Online (Sandbox Code Playgroud)

工厂函数需要以某种方式添加到字典中。为此,您可以公开注册(也可能取消注册)方法。