在这种情况下使用多态而不是枚举有啥好处吗?

Posted

技术标签:

【中文标题】在这种情况下使用多态而不是枚举有啥好处吗?【英文标题】:Is there any benefit about using Polymorphism over Enum in this scenario?在这种情况下使用多态而不是枚举有什么好处吗? 【发布时间】:2017-01-16 13:38:56 【问题描述】:

情景

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

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

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

每个类型都有自己的实现:

public class FilterTypeInteger : FilterType

    public override string Replace(string baseString,string oldValue, string newValue)
    
        //Do logic to replace for an Integer type
    

问题

SOLID 解决方案适用于我的测试,但在生产代码中,Database 中有一个 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) 是否有另一种方法可以在不使用 switch ou if-else 子句的情况下将 SOLID OCP 原则同时保留在数据库和业务代码中?

【问题讨论】:

如果您正在构建 SQL 语句,为什么不使用库和准备好的语句来为您处理这些事情? 查询是通过现有的用户界面创建的,因此它必须支持模板中定义的占位符。它还必须支持级联查询这就是我决定构建自己的组件的原因。 【参考方案1】:

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

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

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

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

例如

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

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

【讨论】:

这是一个很好的解决方案。我认为从中吸取的教训是:有时不使用 SOLID 是可以的,但要保持良好的模式。我会更多地搜索你提到的那些库。 @DaniloRuziska SOLID 原则是指导方针,但您必须保持务实。如果静态工厂完成了工作,那么最好坚持使用它,而不是构建一个非常复杂的可扩展机制,允许在不需要时自动发现新的过滤器类型。 @plalx 奥卡姆剃刀是“违反”原则的好借口。 @CSharpie 仅当我们假设更简单通常会导致软件开发更好,但我认为我们可以;)

以上是关于在这种情况下使用多态而不是枚举有啥好处吗?的主要内容,如果未能解决你的问题,请参考以下文章

枚举类

使用抽象类而不是特征有啥好处?

通过尽可能多地定义常量而不是变量,Swift 有啥好处吗?

枚举和命名元组有啥区别?

java 为啥枚举能不用最好不要用呢?有啥问题吗

枚举还有这样的用法你知道吗