我必须获取一些数据,并将大量可能的变量应用于它。我真的不喜欢使用一组巨大的if语句的想法,所以我正在寻求一种简化方法的帮助,并使其更容易维护。
举个例子:
if (isSoccer)
val = soccerBaseVal;
else if (isFootball)
val = footballBaseVal;
.... // 20 different sports
if (isMale)
val += 1;
else
val += 5;
switch(dayOfWeek)
{
case DayOfWeek.Monday:
val += 12;
...
}
等..等等..可能在100-200种不同的测试和配方变化范围内。
这似乎是一场维护噩梦。有什么建议吗?
编辑:
为了进一步增加问题,许多变量仅在某些情况下使用,因此它不仅仅是具有不同值的固定逻辑集。逻辑本身必须基于条件而改变,可能是从先前变量应用的条件(例如,如果val>阈值)。
所以是的,我同意对许多值使用查找,但我也必须有可变逻辑。
答案 0 :(得分:7)
避免大型交换结构的常用方法是将信息放入数据结构中。创建包含关联值的枚举SportType
和Dictionary<SportType, Int32>
。您只需编写val += sportTypeScoreMap[sportType]
即可完成。
此模式的变化将在许多类似的情况下帮助您。
public enum SportType
{
Soccer, Football, ...
}
public sealed class Foo
{
private static readonly IDictionary<SportType, Int32> sportTypeScoreMap =
new Dictionary<SportType, Int32>
{
{ Soccer, 30 },
{ Football, 20 },
...
}
private static readonly IDictionary<DayOfWeek, Int32> dayOfWeekScoreMap =
new Dictionary<DayOfWeek, Int32>
{
{ DayOfWeek.Monday, 12 },
{ DayOfWeek.Tuesday, 20 },
...
}
public Int32 GetScore(SportType sportType, DayOfWeek dayOfWeek)
{
return Foo.sportTypeScoreMap[sportType]
+ Foo.dayOfWeekScoreMap[dayOfWeek];
}
}
答案 1 :(得分:1)
使用switch语句或过滤器功能。
通过过滤功能,我的意思是:
func filter(var object, var value)
{
if(object == value)
object = valueDictionary['value'];
}
然后将过滤器应用于:
filter(theObject, soccer)
filter(theObject, football)
请注意,使用字典可以更好地使用过滤器,但这不是必需的。
答案 2 :(得分:1)
来自Pragmatic Programmer,您可以使用DSL来封装规则并编写流程引擎。对于您提出的问题,解决方案可能如下所示:
MATCH{
Soccer soccerBaseVal
IsMale 5
!IsMale 1
}
SWITCH{
Monday 12
Tuesday 13
}
然后匹配MATCH的第一个col中的所有内容,以及每个SWITCH中的第一个项目。您可以制作任何您想要的语法,然后只需编写一些脚本来将其填入代码中(或使用Xtext,因为它看起来很酷)。
答案 3 :(得分:1)
以下是一些想法:
1使用查找表:
var val = 0;
SportType sportType = GetSportType();
val += sportvalues[sportType];
您可以从数据库加载表。
2使用工厂模式:
var val = 0;
val += SportFactory.Create(sportType).CalculateValue();
Dynamic Factory Pattern在新的(运动)类型经常添加到代码中的情况下非常有用。此模式使用反射来防止更改工厂类(或任何全局配置)。它允许您只需在代码中添加一个新类。
当然,在您的情况下使用动态工厂甚至工厂都可能过度。你是唯一能说出来的人。
答案 4 :(得分:0)
作为第一步,我可能会将每个逻辑处理区域分解为自己的方法:(可能不是最佳名称作为第一遍)
EnforceSportRules
ProcessSportDetails
EnforceGenderRules
接下来,根据规则的复杂程度,我可以将每个部分分解为自己的类,并让它们由主类(如工厂)处理。
GenderRules
GenderContext
答案 5 :(得分:0)
我没有什么特别的东西可以提供给你,而不是首先建议不要把它作为一个大块 - 把它分成几个部分,在重要部分之间做出评论分隔。
另一个建议是,如果您要进行许多非常短的测试,例如,从惯例中断,并将val增量器放在与评估和缩进相同的行上,以便它们彼此对齐。
if (isSoccer) val = soccerBaseVal;
if (isMale) val += 1;
else val += 5;
switch(dayOfWeek){
case DayOfWeek.Monday: val += 12;
...
}
多余的空白可以将这百个事物变成几百行,使得垂直滚动过度,难以全面了解事物。
答案 6 :(得分:0)
如果你真的只是在这种类型中添加值,我会创建一个枚举,其中定义的索引对应于数组中的存储值。然后你可以做这样的事情:
enum Sport
{
football = 0,
soccer = 1,
//...
}
int sportValues[] = {
/* footballValue */,
/* soccerValue */,
/* ...Values */
};
int ApplyRules(Sport sport, /* other params */)
{
int value = startingValue;
value += sportValues[(int)sport];
value += /* other rules in same fashion */;
}
答案 7 :(得分:0)
考虑实现利用继承/多态的Strategy Pattern来管理个人功能。通过将每个功能分成自己的专用课程,您可以放弃长达数英里case
个句号或if
语句的噩梦。
不确定C#是否支持(或永远不会)但是VB.NET将XML Comment CompletionList指令集成到intellisense中,当与策略模式结合使用时,它可以让您轻松使用一个具有OO开放式可扩展性的枚举。