更换大开关?

O.O*_*O.O 5 .net c# asp.net design-patterns

我有一个名为"ReportController.aspx"的页面,其目的是基于查询字符串参数实例化报表(类)

        switch (Request.QueryString["Report"])
        {                
            case "ReportA":
                CreateReportAReport("ReportA's Title");
                break;
            case "ReportB":
                CreateReportBReport("ReportB's Title");
                break;                
            case "ReportC":
                CreateReportCReport("ReportC's Title");
                break;
            case "ReportD":
                CreateReportDReport("ReportD's Title");
                break;
                ...
Run Code Online (Sandbox Code Playgroud)

基本上,每次需要新报告时,都会有添加案例和添加方法的开销.这个switch语句可能会变得非常长.我读过可以使用Dictionary将报告映射到?.这看起来如何使用字典(假设这是一种更好的方式).

此外,CreateReportXReport方法基本上将一堆额外的QueryString值传递给报表类的构造函数(每个报表类都有不同的构造函数).

Pat*_*her 6

没有必要在某处输入新信息; 关键是要将其从代码中删除,以避免重新编译和重新部署以进行这种微不足道的更改.

一些好的选择是在XML配置文件中列出这些值,或者更好的是在数据库中列出这些值.

无论来源如何,您可能都希望用这些数据填写字典.这将:

  • 使缓存更容易
  • 制作干净,快速的代码

当您将数据从配置中提取到代码中时,您需要将项添加到字典中,如下所示:

Dictionary<string, IReportCreator> = configDataGetter.GetReportDataFromDB().
    ToDictionary(r => r.Name, myReportCreatorFactory(r => r.ReportID))
Run Code Online (Sandbox Code Playgroud)

此示例假定您将数据作为某种实体对象获取,并使用工厂为您的代码创建报告使用策略模式.当然,你有多种方法可以做到这一点.

我假设报告过于广泛,多样,性质不同,你不能只在数据库中放置sql和样式构建块?

根据op的评论进行编辑:

啊,抓住了.好吧,我不知道你有多少时间,但是就像你把所有东西都推到某种工厂一样,你有更好的选择.我将从一些类似的事情中给你一些希望有所帮助的想法.每个步骤本身都是一个改进,但也是一个很好的步骤,以真正将报告逻辑与此shell代码分开.此外,我可以看到你已经知道你正在做什么,我肯定知道我将在下面说些什么,但我不知道你知道什么,这对其他人有帮助.

首先,从代码中提取任何信息到db(如果你还没有),并在改进设置时添加更多数据库字段(和一两个表).

你可能已经知道了,但我会为其他人提一下,看看我上面提到的策略模式.您可以将每个"报表函数"的自定义逻辑实际放在各种策略类的构造函数中.它们都将从您的基础ReportGenerator继承(或使用常见的IReportGenerator接口).他们可以而且应该共享相同的构造函数; 变量报告参数将由字典类型的参数处理.每个类的构造函数实现都知道变量的类型是需要的(来自db配置),并相应地转换/使用它们.

下一步可能是使用反射来真正摆脱工厂中的select语句.您必须将类的名称作为db中报告配置数据的一部分(并且具有公共构造函数).

此时,添加新报告的方式非常简洁,即使您每次都必须添加新类.那么好.它履行单一责任开放封闭的原则.

现在,只是从应用程序删除类的最后一步,因此可以动态添加/编辑它们.查看MEF.这就是它的目的.您可能在互联网上找到的一些您可能不应该使用的东西是CodeDom(当没有别的东西时很棒,但MEF更好)和.NET 5中的编译即服务功能.MEF是这样的去.


das*_*ght 4

假设所有报告都实现IReport,您可以使用 来完成Func<IReport>,如下所示:

IDictionary<string,Func<IReport>> dictToReport = new Dictionary {
    {"ReportA", () => CreateReportAReport("ReportA's Title") }
,   {"ReportB", () => CreateReportBReport("ReportB's Title") }
,   ...
};
Run Code Online (Sandbox Code Playgroud)

然后您可以使用以下代码替换开关:

var myReport = dictToReport[Request.QueryString["Report"]]();
Run Code Online (Sandbox Code Playgroud)

  • 然后,您仍然需要为每个新报告向字典添加一个项目 - 从概念上讲,它是相同的。 (2认同)