Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在这种情况下,在Enum上使用多态性有什么好处吗?_C#_Enums_Solid Principles_Open Closed Principle - Fatal编程技术网

C# 在这种情况下,在Enum上使用多态性有什么好处吗?

C# 在这种情况下,在Enum上使用多态性有什么好处吗?,c#,enums,solid-principles,open-closed-principle,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子句中要替换的数据可以是一个整数、一个字符串、一个日期,并且每个数据都有不同的行为(例如:在字符串大小写中的值

场景

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

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

SELECT DISTINCT ID, NAME AS VALUE FROM EVENTS
WHERE {{ESTABLISHMENTFILTER.ID}} IS NULL OR ESTABLISHMENT_ID =   {{ESTABLISHMENTFILTER.ID}}
where子句中要替换的数据可以是一个整数、一个字符串、一个日期,并且每个数据都有不同的行为(例如:在字符串大小写中的值周围包含单引号)

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

public enum FilterType
{
    Integer,
    String
}
并像这样使用它(例如在业务层中)

我还在我的代码中应用坚实的原则,我发现这可能会破坏OCP。所以我重构了一个基类

public abstract class FilterType
{
    public abstract string Replace(string baseString, string oldValue, string newValue);
}
每种类型都有自己的实现:

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

固溶体对我的测试有效,但在生产代码中,数据库中有一个int列用于确定类型。因此,我基本上是将“switch case”逻辑传输到数据层,数据层必须检查此列以实例化正确的FilterType(下面的代码是一个伪代码,因为我还没有实现它):

问题

1) 实现上述“if-else”逻辑的方法是否破坏了OCP?因为如果创建了一个新类型,则必须实现一个新的else子句
2) 是否有另一种方法可以在不使用switch-ou-if-else子句的情况下将可靠的OCP原则保留在数据库和业务代码中?

将确保决策只需发生一次,因此这可能是一个好主意。如果您在某个时候对每种类型都有额外的专门操作,那么它们应该很容易实现

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

但是,如果您希望通过设计和运行时进行扩展,那么这将无法实现,您需要引入一种允许在运行时发现/注册新类型的方法

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

例如


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

如果您正在构建SQL语句,为什么不使用库和准备好的语句来为您处理这些事情呢?查询是通过现有的用户界面创建的,因此,它必须支持模板中定义的占位符。它还必须支持级联查询,这就是我决定构建自己的组件的原因。这是一个很好的解决方案。我认为从中得到的教训是:有时不使用实体但保持良好的模式是可以的。我将搜索更多关于你提到的那些库的信息。@DaniloRuziska坚实的原则是指导原则,但你必须保持务实。如果一个静态工厂完成了这项工作,那么最好还是坚持下去,而不是建立一个非常复杂的可扩展机制,允许在不需要时自动发现新的过滤器类型。@plalx Occam的剃须刀是“违反”原则的一个很好的借口。@CSharpie前提是我们假设简单通常会导致更好的性能软件开发,但我认为我们可以;)
public class FilterTypeInteger : FilterType
{
    public override string Replace(string baseString,string oldValue, string newValue)
    {
        //Do logic to replace for an Integer type
    }
}
    if (dataReader["FILTERTYPE"] == 1)
        filter.Type = new FilterTypeInteger();
    else if (dataReader["FILTERTYPE"] == 2)
        filter.Type = new FilterTypeString();
filterTypeFactory.RegisterFilter(1, typeof(FilterTypeInteger));