2011-04-30 57 views
3

我们的C#应用​​程序生成各种类型的报告。每种类型的报告都有一个xml模式,用于定义可用的选项和功能,因此用户可以创建一个描述他们想要的报告的XML文档。有多种报表类型通用的元素,并且某些元素之间存在相互依赖关系。需要重构大类的建议

我们目前有一个完整的静态方法来处理xml的解析。它将采用模式验证的文档,并返回一个代表报告类型和其配置选项的对象。该类看起来像这样:

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 
    } 
    ... 
} 

我相信目的是封装xml结构的细节,我认为它的确如此。它也不会受到重复代码的影响。但它非常大,很难阅读,而且随着我们添加更多功能而变得更糟。测试也很困难,因为它严重依赖按正确顺序完成的事情。

我想重构它,但到目前为止,我能想到的唯一事情就是将它分成多个类;比如说,每个报告类型都有一个类,常见的东西还有一个辅助类。但它仍然是混乱的,甚至可能更难以阅读。有没有一种很好的方法来组织这样的事情?任何可能有帮助的模式?我看了一大堆创作模式,并没有真正发现任何看起来合适的东西。

更新:对不起,我没有时间或预算来实际工作这个重构,但谢谢你的建议。我越想它,我就越喜欢(例如)责任链的想法。起点(公共函数)将创建返回对象并填充一些基本内容,然后将对象和xml移交到下一个片段。每件作品都会知道对象的哪些部分和它需要的xml,并且可以通过查看对象的更改来独立测试每件作品。

+0

您的计划将其分成多个类是否包含使用包含公共代码的基类的继承?我会看那个。但是,这取决于你需要什么样的逻辑才能实现它。另一个不错的方法是,如果可以创建一个包含每个XML结构的实例数据的结构或类,然后编写一个可以从该数据产生正确结果的泛型类。 – 2011-04-30 14:20:05

回答

0

我想你会需要一些模式和原则来提高你的课程。您已经在使用工厂模式。你似乎正在描述的问题是处理活动的具体顺序,并将你的课程分成更小的块。

为了处理活动的顺序,它看起来像你可以use a chain of responsibility pattern.

由于依赖关系,解决方案“部分”的可测试性注释中,其中一部分是测试设置(您需要更好的模拟或存根来支持方法的活动),也许更好的设计会希望出来你的努力测试应用程序。

0

我希望有一些方法可以利用继承,并使用适当的构造函数而不是工厂(我没有看到需要工厂)。此外,将报表专用功能仅应用于所应用的报表以及仅适用于其功能的功能特定功能将会很好。例如:

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 
    } 
    } 
} 
0

一个相当常见的方法是使用策略模式。你可以有一个返回IReport的IReportBuilder接口。然后每个具体的报告生成器将封装构建报告的具体细节(可能使用通用代码的基类)。类似地,'特征'可以遵循这种模式,具体的特征被注入具体的报告中。

我不确定客户如何选择报告;但是一个工厂可以用来基于关键字实例化正确的具体报告生成器(这可能会更好一些)。

0

我会尝试以下

  1. 创建ReportType抽象和具体的各自类别。返回类型CreateReportTypeX()将是抽象类型。报告列举可能有助于统一CreateReportX()成一个单一的CreateReport()
  2. 同样Feature抽象和具体的功能classes.A参数对象并为CreateFeatureX()功能枚举。
  3. ReportFactory只能处理CreateReport()。对于CreateFeature(),我们可能需要FeatureFactory