在这种情况下,使用多态性而不是Enum有什么好处吗?

时间:2017-01-16 13:38:56

标签: c# enums solid-principles open-closed-principle

情景

我正在创建一个动态查询构建器以发送到另一个组件(报表生成器)。

查询的某些部分有占位符。例如:

SELECT DISTINCT ID, NAME AS VALUE FROM EVENTS
WHERE {{ESTABLISHMENTFILTER.ID}} IS NULL OR ESTABLISHMENT_ID =   {{ESTABLISHMENTFILTER.ID}}

where子句中要替换的数据可以是Integer,String,Date,每个都有不同的行为(例如:在字符串的情况下包含单引号)。

我的第一个方法是创建一个枚举:

public enum FilterType
{
    Integer,
    String
}

并像这样使用它(例如在业务层中)

switch (filter.Type)
{
   case FilterType.Integer:
        //Do replace logic for an integer
        break;
   case FilterType.String:
        //Do replace logic for a string
        break;
   default:
        break;
}

我也将SOLID原则应用于我的代码,我发现这可能会破坏OCP。所以我重构了使用基类

public abstract class FilterType
{
    public abstract string Replace(string baseString, string oldValue, string newValue);
}

并且每个Type都有自己的实现:

public class FilterTypeInteger : FilterType
{
    public override string Replace(string baseString,string oldValue, string newValue)
    {
        //Do logic to replace for an Integer type
    }
}

问题

SOLID解决方案适用于我的测试,但在生产代码中,数据库中有一个int列来确定类型。所以我基本上转移了' switch-case'数据层的逻辑,必须检查此列以实例化正确的FilterType(下面的代码是伪代码,因为我还没有实现它):

    if (dataReader["FILTERTYPE"] == 1)
        filter.Type = new FilterTypeInteger();
    else if (dataReader["FILTERTYPE"] == 2)
        filter.Type = new FilterTypeString();

问题

1)实施' if-else'的方法上面的逻辑打破了OCP?因为如果创建了新的Type,则必须实现新的else子句 2)是否有另一种方法可以将SOLID OCP原则保留在数据库和业务代码中,而无需使用switch if if-else子句?

1 个答案:

答案 0 :(得分:1)

Replacing conditional with polymorphysim将确保决策只需要发生一次,所以这可能是一个好主意。如果您在某些时候对每种类型都有其他专门操作,那么它们应该易于实现。

现在,为了创建具体类型,您可以将此逻辑封装在工厂中。在它最简单的形式中,工厂将是具有大型switch语句的静态工厂。它并不尊重OCP,但在大多数情况下它仍然是可接受的设计。

但是,如果您希望通过设计进行扩展,并且在运行时无法进行扩展,则需要引入一种允许在运行时发现/注册新类型的方法。

这可以通过多种方式完成,但一个例子就是在工厂设置一个允许您注册新类型的方法。

E.g。

filterTypeFactory.RegisterFilter(1, typeof(FilterTypeInteger));

无论如何,在您拥有并构建自己的SQL语句构建器之前,您应该查看现有的库。您可能有一个中间DSL(您的模板)被解析为AST,然后处理此AST以生成SqlCommand或类似的东西。