Pau*_*ick 5 c# design-patterns switch-statement
这个问题可能以前发过,但我找不到了.
我已经写了这么长时间的东西,我坐下来写一些新东西,然后开始输入这个就好像它是我自己的模式.最近出现了一个项目,我发现自己正在查看自己的代码并开始思考它看起来有多臭.
BackgroundInfoIfYouCare
Run Code Online (Sandbox Code Playgroud)
在这个特定的库中,我需要向用户发送电子邮件.到目前为止,有13个固定电子邮件.
每封电子邮件都有自己的模板(我使用的是Razor解析器,因此模板是用cshtml编写的).每个电子邮件模板都有一个名称密钥字符串.每封电子邮件都有自己的EF4查询,以根据"成员资格"实体和所有相关数据返回模型.
我有一个接受字符串的类,这是一个电子邮件模板名称密钥.
该方法将运行相应的查询并返回列表,抓取电子邮件模板.
列表和模板将传递给解析器,以将每个成员资格合并到模板中,并返回列表电子邮件.
EndOfBackgroundInfoIfYouCare
Run Code Online (Sandbox Code Playgroud)
真正的问题是......最好的方法是什么?
一种方法是只使用一个开关
public List<Membership> Execute(string TemplateKey) {
switch (TemplateKey)
{
case "SomethingExpired":
QueryResult = new SomethingExpiredEmailQuery().ExecuteQuery();
break;
case "SomethingExpireIn30":
QueryResult = new SomethingExpireIn30EmailQuery().ExecuteQuery();
break;
case "FirstTimeLoginThanks":
QueryResult = new FirstTimeLoginThanksEmailQuery().ExecuteQuery();
break;
case "SecurityTraining":
QueryResult = new SecurityTrainingEmailQuery().ExecuteQuery();
break;
case ETC ETC ETC...
Run Code Online (Sandbox Code Playgroud)
}
另一种方法是使用接口
IEmailQuery
void ExecuteQuery()
Run Code Online (Sandbox Code Playgroud)
但是如果我使用接口,我仍然需要实例化Query类.它不会保存任何代码,也不会使代码更易于维护.
通过反射,我可以使用模式命名所有电子邮件查询:电子邮件模板SecurityTraining的密钥具有SecurityTrainingEmailQuery的查询名称,我可以使用反射来实例化并调用ExecuteQuery方法.
如果不使用反射,是否有更清洁的连线方式?
一种选择是拥有Dictionary<string, Func<IEmailQuery>>地图.你可以像这样构建它:
private static readonly Dictionary<string, Func<IEmailQuery>> MailQueryMap =
new Dictionary<string, Func<IEmailQuery>> {
{ "SomethingExpired", () => new SomethingExpiredMailQuery() },
{ "SomethingExpireIn30", () => new SomethingExpireIn30EmailQuery() },
// etc
};
Run Code Online (Sandbox Code Playgroud)
然后:
public List<Membership> Execute(string templateKey) {
IEmailQuery query = MailQueryMap[templateKey].Invoke();
var queryResult = query.ExecuteQuery();
// ...
}
Run Code Online (Sandbox Code Playgroud)
如果你可以保证你只需要无参数构造函数,你总是可以存储Dictionary<string, Type>并通过反射实例化它 - 但是会有一些丑陋的转换等.
编辑:当然,如果模板的名称始终是类型的名称,您可以使用
Type queryType = Type.GetType(namespacePrefix + "." + templateKey);
IEmailQuery query = (IEmailQuery) Activator.CreateInstance(queryType);
var queryResult = query.ExecuteQuery();
Run Code Online (Sandbox Code Playgroud)
您可能还想考虑使用枚举而不是魔术字符串常量.
小智 3
事实上,这对我来说看起来不太臭。如果您不喜欢 switch 语句,您可以转到 IEmailQuery-Path 并将其连接到Dictionary<string,IEmailQuery>. 这可能会节省一些代码行,因为您可以像这样访问它:
QueryDictionary["MyKey"].ExecuteQuery();
Run Code Online (Sandbox Code Playgroud)
干杯,奥利弗