我继承了以下(可怕的)代码,并且想知道如何最好地重构它。
代码库中有大量的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不应该使用基类型,也许应该有多个方法,每个派生类型一个?
答案 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 ); }
}
通过访问者的双重调度删除了类型检查,这更加优雅。
我并不完全清楚各种历史与各种物品的关系。所以这只是一个可能的方向草图。