设计模式,用相关对象删除多个if / else子句

时间:2010-02-18 11:44:09

标签: c# design-patterns

我继承了以下(可怕的)代码,并且想知道如何最好地重构它。

代码库中有大量的if / else子句,其中一个类似于下面的内容:

public class BaseResultItem
{
    public int Property1 { get; set; }
}

public class ResultItem1 : BaseResultItem
{
    public int Property2 { get; set; }
}

public class ResultItem2 : BaseResultItem
{
    public int Property3 { get; set; }
}

public class BaseHistoryItem
{
    public int Property1 { get; set; }
}

public class HistoryItem1 : BaseHistoryItem
{
    public int Property2 { get; set; }
}

public class HistoryItem2 : BaseHistoryItem
{
    public int Property3 { get; set; }
}

public class HistoryBuilder
{
    public BaseHistoryItem BuildHistory(BaseResultItem result)
    {
        BaseHistoryItem history = new BaseHistoryItem            
        {
            Property1 = result.Property1
        };

        if (result is ResultItem1)
        {
            ((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
        }
        else if (result is ResultItem2)
        {
            ((HistoryItem2)history).Property3 = ((ResultItem2)result).Property3;
        }

        return history;
    }
}

请注意,这是一个简化示例,实际代码中涉及的类更多。整个地方都有类似的if / else子句。

我一直在看抽象工厂模式,但我遇到了一些问题。

基本上我假设要避免if / else问题我需要传递实际的衍生类型。所以BuildHistory不应该使用基类型,也许应该有多个方法,每个派生类型一个?

3 个答案:

答案 0 :(得分:1)

一般的“设计模式”只是使用具有多态性的对象方向而不是类型检查。因此:BaseResultItem中的BuildHistory方法,由后代覆盖。

检查对象的具体类型的任何代码都会闻起来(在重构意义上)。支持不同类型的不同行为是OO的意义所在。

答案 1 :(得分:1)

如果您无法更改DTO类,您可以尝试将HistoryBuilder子类化以处理不同的子类。然后使用适当的HistoryBuilderX从ResultItem创建HistoryItem。那么问题是如何为所提供的ResultItem获取适当的HistoryBuilderX。

但是,如果您无法更改BaseResultItem类以包含GetBuilder函数,则需要使用一些if..else if ..构造来检查ResultItem的classtype类型。

或者您创建一个Registry,其中每个ResultItem类都使用其对应的HistoryBuilderX类进行注册。但这可能有点矫枉过正。

答案 2 :(得分:0)

使用多态删除类型检查。

if (result is ResultItem1)
{
    ((HistoryItem1)history).Property2 = ((ResultItem1)result).Property2;
}

变成类似

的东西
result.addToHistory( history );

如果出于某种原因,您不想在项目类中分散逻辑,请查看visitor pattern。在这种情况下,你有类似的东西:

public class Visitor {
     History history;
     public visit ( ResultItem1 item )  { ... }
     public visit ( ResultItem2 item )  { ... }
     ...
}

public class ResultItem1 {
     public accept( Visitor v ) { v.visit( this ); }
}

通过访问者的双重调度删除了类型检查,这更加优雅。

我并不完全清楚各种历史与各种物品的关系。所以这只是一个可能的方向草图。