C# 需要重构大型类的建议吗
我们的C#应用程序生成各种类型的报告。每种类型的报告都有一个xml模式,定义了可用的选项和功能,因此用户可以创建一个xml文档来描述他们想要的报告。存在多个报表类型通用的元素,并且某些元素之间存在相互依赖关系 目前,我们有一个完整的静态方法类来处理xml的解析。它将获取一个经过模式验证的文档,并返回一个表示报告类型及其配置选项的对象。这个类看起来像这样:C# 需要重构大型类的建议吗,c#,refactoring,C#,Refactoring,我们的C#应用程序生成各种类型的报告。每种类型的报告都有一个xml模式,定义了可用的选项和功能,因此用户可以创建一个xml文档来描述他们想要的报告。存在多个报表类型通用的元素,并且某些元素之间存在相互依赖关系 目前,我们有一个完整的静态方法类来处理xml的解析。它将获取一个经过模式验证的文档,并返回一个表示报告类型及其配置选项的对象。这个类看起来像这样: public class ReportFactory { //let's say 4 types of reports pub
public class ReportFactory
{
//let's say 4 types of reports
public static ReportType1 CreateReportType1(XDocument document)
{
//logic to create this type of report, calling private methods in this class
}
....
public static ReportTypeN CreateReportTypeN(XDocument document)
{
//logic to create this type of report
}
//several dozen private methods, which get called from the public methods or from each other
private static Feature1 CreateFeature1(XElement element)
{
//create some feature of a report
}
private static FeatureN CreateFeatureN(XElement element, FeatureM m)
{
//create some feature which relies on another previously built feature
}
private static FeatureX CreateFeatureX(ReportType2 report, XElement elementForX, XElement elementRelatedToX)
{
//create some feature, which relies on
//more than one element and/or a partially built report of a given type
}
private static void UpdateFeatureNWithStuffFromFeatureM(FeatureN n, FeatureM m)
{
//modify parts of the built report, based on some other parts of the report
}
...
}
public class Report
{
protected Report(XDocument document)
{
// Any code common to creating the majority of reports
}
protected class Feature
{
private XElement element;
public Feature(XElement element)
{
// Any code common to creating the majority of features
}
public Feature(Feature feature)
{
element = feature.element;
// Any code common to creating features from other features
}
}
public class Feature1 : Feature
{
public Feature1(XElement element)
: base(element)
{
// Any code specific to creating Feature1
}
}
public class FeatureN : Feature
{
public FeatureN(FeatureM feature) : base(feature)
{
// Any code specific to creating a featureN from a featureM
}
public void UpdateFromFeatureM(FeatureM feature)
{
//modify parts of the built report, based on some other parts of the report
}
}
public class FeatureM : Feature
{
}
}
public class ReportType1 : Report
{
public ReportType1(XDocument document)
: base(document)
{
// Code specific to creating ReportType1
}
}
public class ReportType2 : Report
{
public ReportType2(XDocument document)
: base(document)
{
// Code specific to creating ReportType2
}
public class FeatureX
{
public FeatureX(ReportType2 report, XElement element, XElement relatedElement)
{
//create some feature, which relies on
//more than one element and/or a partially built report of a given type
}
}
}
我相信其目的是封装xml结构的细节,我想它确实做到了。它也不会因为重复的代码而受到太多的影响。但它非常大,很难阅读,而且随着我们添加更多功能,它会变得更糟。它也很难测试,因为它严重依赖于以正确的顺序完成的事情
我想重构它,但到目前为止,我唯一能想到的就是将它拆分成多个类;比如说,每个报表类型都有一个类,而普通内容则有一个附加的助手类。但它仍将是混乱的,甚至可能更难阅读。有没有一个好的方法来组织这样的事情?有什么可能有用的模式吗?我已经研究了一系列的创作模式,但还没有找到任何适合的模式
更新:很抱歉,我没有时间或预算来进行这项重构工作,但是谢谢你的建议。我想得越多,我就越喜欢责任链的理念。起点(公共函数)将创建返回对象并填写一些基本内容,然后将对象和xml交给下一部分。每个部分都将知道对象的哪些部分及其所需的xml,并且每个部分都可以通过查看对象的更改进行独立测试。我猜您将需要几种模式和原则来增强您的类。您已经在使用factory模式。不过,您似乎要描述的问题是如何处理活动的特定顺序,并将类分解为更小的块 为了处理活动的排序,看起来您可以
注意,由于依赖关系,解决方案的“部分”具有可测试性,其中的一部分是测试设置(您需要更好的模拟或存根来支持方法的活动)以及可能更好的设计,这将有望从您测试应用程序的努力中产生 我希望有某种方法可以利用继承并使用适当的构造函数而不是工厂(我不认为需要工厂)。另外,最好只在应用报表的报表中添加特定于报表的功能,而只在应用报表的功能中添加特定于功能的功能。大概是这样的:
public class ReportFactory
{
//let's say 4 types of reports
public static ReportType1 CreateReportType1(XDocument document)
{
//logic to create this type of report, calling private methods in this class
}
....
public static ReportTypeN CreateReportTypeN(XDocument document)
{
//logic to create this type of report
}
//several dozen private methods, which get called from the public methods or from each other
private static Feature1 CreateFeature1(XElement element)
{
//create some feature of a report
}
private static FeatureN CreateFeatureN(XElement element, FeatureM m)
{
//create some feature which relies on another previously built feature
}
private static FeatureX CreateFeatureX(ReportType2 report, XElement elementForX, XElement elementRelatedToX)
{
//create some feature, which relies on
//more than one element and/or a partially built report of a given type
}
private static void UpdateFeatureNWithStuffFromFeatureM(FeatureN n, FeatureM m)
{
//modify parts of the built report, based on some other parts of the report
}
...
}
public class Report
{
protected Report(XDocument document)
{
// Any code common to creating the majority of reports
}
protected class Feature
{
private XElement element;
public Feature(XElement element)
{
// Any code common to creating the majority of features
}
public Feature(Feature feature)
{
element = feature.element;
// Any code common to creating features from other features
}
}
public class Feature1 : Feature
{
public Feature1(XElement element)
: base(element)
{
// Any code specific to creating Feature1
}
}
public class FeatureN : Feature
{
public FeatureN(FeatureM feature) : base(feature)
{
// Any code specific to creating a featureN from a featureM
}
public void UpdateFromFeatureM(FeatureM feature)
{
//modify parts of the built report, based on some other parts of the report
}
}
public class FeatureM : Feature
{
}
}
public class ReportType1 : Report
{
public ReportType1(XDocument document)
: base(document)
{
// Code specific to creating ReportType1
}
}
public class ReportType2 : Report
{
public ReportType2(XDocument document)
: base(document)
{
// Code specific to creating ReportType2
}
public class FeatureX
{
public FeatureX(ReportType2 report, XElement element, XElement relatedElement)
{
//create some feature, which relies on
//more than one element and/or a partially built report of a given type
}
}
}
一种相当常见的方法是使用策略模式。您可以有一个返回IReport的IReportBuilder接口。然后,每个具体的报表生成器将封装构建报表的细节(可能有一个用于公共代码的基类)。类似地,“Features”可以遵循这种模式,将适当的Features具体类注入到具体的报告中
我不确定客户如何选择报告;但是,可以使用工厂根据一个键来实例化正确的具体报表生成器(举个例子可能更好)。我将尝试以下方法
ReportType
抽象和相应的具体类。CreateReportTypeX()
的返回类型将是抽象类型。报表枚举有助于将CreateReportX()
统一为单个CreateReport()
Feature
抽象和具体的要素类。CreateFeatureX()
的参数对象和要素枚举ReportFactory
应仅处理CreateReport()
。对于CreateFeature()
,我们可能需要FeatureFactory
您将其拆分为多个类的计划是否包括使用包含公共代码的基类的继承?我会看的。但这取决于你需要什么样的逻辑才能使它变得干净。另一个不错的方法是,如果可以创建一个包含每个XML结构实例数据的结构或类,然后编写一个泛型类,从该数据生成正确的结果。