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值传递给报表类的构造函数(每个报表类都有不同的构造函数).
没有必要在某处输入新信息; 关键是要将其从代码中删除,以避免重新编译和重新部署以进行这种微不足道的更改.
一些好的选择是在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是这样的去.
假设所有报告都实现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)