我有一个名为“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;
...
基本上,每次需要新报告时,都会有添加案例和添加方法的开销。这个switch语句可能会变得非常长。我读过可以使用Dictionary将报告映射到?。如何使用字典(假设这是一种更好的方式)。
此外,CreateReportXReport
方法基本上将一堆额外的QueryString值传递给报表类的构造函数(每个报表类都有不同的构造函数)。
答案 0 :(得分:6)
没有必要在某处输入新信息;关键是要将其从代码中删除,以避免重新编译和重新部署以进行这种微不足道的更改。
一些好的选择是在XML配置文件中列出这些值,或者更好的是在数据库中列出。
您可能希望用这些数据填写字典,无论来源如何。这将:
当需要将数据从配置中提取到代码中时,您需要将项目添加到字典中,如下所示:
Dictionary<string, IReportCreator> = configDataGetter.GetReportDataFromDB().
ToDictionary(r => r.Name, myReportCreatorFactory(r => r.ReportID))
此示例假定您将数据作为某种实体对象获取,并使用工厂将strategy pattern用于创建报告的代码。当然,你有多种方法可以做到这一点。
我认为报告过于广泛,多样,性质不同,你不能只在数据库中放置sql和样式构建块?
根据op的评论修改:
啊,好吧。好吧,我不知道你有多少时间,但是就像你把所有东西都推到某种factory那样,你有更好的选择。我将从一些类似的事情中给你一些希望有所帮助的想法。每个步骤本身都是一个改进,但也是一个很好的步骤,以真正将报告逻辑与此shell代码分开。此外,我可以看到你已经知道你正在做什么,我肯定知道下面我会说些什么,但我不知道你知道什么,这对其他人有帮助。首先,将所有信息从代码中提取到数据库(如果还没有),并且在改进设置时添加更多数据库字段(以及一两个表)。
你可能已经知道了,但我会为其他人提一下,看看我上面提到的策略模式。您可以将每个“报表函数”的自定义逻辑实际放在各种策略类的构造函数中。它们都将从您的基础ReportGenerator继承(或使用常见的IReportGenerator接口)。他们可以而且应该共享相同的构造函数;变量报告参数将由字典类型的参数处理。每个类的构造函数实现都知道变量的类型是需要的(来自db配置),并相应地转换/使用它们。
下一步可能是使用reflection真正摆脱工厂中的select语句。您必须将该类的名称作为db中报告配置数据的一部分(并且具有公共构造函数)。
此时,添加新报告的方式非常简洁,即使您每次都必须添加新类。那么好。它符合single responsibility和open-closed原则。
现在,只有从您的应用中删除课程的最后一步,因此可以动态添加/编辑它们。查看MEF。这就是它的目的。你可能在不应该使用的互联网上找到的一些东西是CodeDom(当没有别的东西时很好,但MEF更好)和编译即服务.NET中提供的功能5. MEF是最佳选择。
答案 1 :(得分:4)
假设所有报告都实施IReport
,您可以使用Func<IReport>
执行此操作,如下所示:
IDictionary<string,Func<IReport>> dictToReport = new Dictionary {
{"ReportA", () => CreateReportAReport("ReportA's Title") }
, {"ReportB", () => CreateReportBReport("ReportB's Title") }
, ...
};
然后您可以使用以下代码替换开关:
var myReport = dictToReport[Request.QueryString["Report"]]();
答案 2 :(得分:1)
我认为最好重新设计此代码并将其转换为某些数据库表(“报告”),以保留每个报告的报告列表和ID。
就是这样。
答案 3 :(得分:1)
要使用Dictionary<string, string>
执行此操作,您只需在包含类型中将其构建为静态缓存
public class Container {
private static Dictionary<string, Func<Report>> ReportMap =
new Dictionary<string, Func<Report>>();
static Container() {
ReportMap["ReportA"] = () => CreateReportAReport("ReportA's Title");
ReportMap["ReportB"] = () => CreateReportBReport("ReportB's Title");
// etc ...
}
}
既然构建了地图,您只需在函数中进行查找,而不是switch
Func<Report> func;
if (!ReportMap.TryGetValue(Request.QueryString["Report"), out func)) {
// Handle it not being present
throw new Exception(..);
}
Report report = func();