编程高度复杂的业务/数学规则的最佳方法
我必须获取一段数据,并将大量可能的变量应用于它。我真的不喜欢使用大量 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 > 阈值)。
所以是的,我同意对许多值使用查找,但我也必须有可变逻辑。
I have to take a piece of data, and apply a large number of possible variables to it. I really don't like the idea of using a gigantic set of if statements, so i'm looking for help in an approach to simplify, and make it easier to maintain.
As an example:
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;
...
}
etc.. etc.. etc.. with possibly in the range of 100-200 different tests and formula variations.
This just seems like a maintenance nightmare. Any suggestions?
EDIT:
To further add to the problem, many variables are only used in certain situations, so it's more than just a fixed set of logic with different values. The logic itself has to change based on conditions, possibly conditions applied from previous variables (if val > threshold, for instance).
So yes, i agree about using lookups for many of the values, but I also have to have variable logic.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
避免大型交换结构的常见方法是将信息放入数据结构中。创建一个枚举
SportType
和一个包含关联值的Dictionary
。您只需编写val += sportTypeScoreMap[sportType]
即可完成。这种模式的变体将在许多类似的情况下为您提供帮助。
A common way to avoid large switching structures is to put the information into data structures. Create an enumeration
SportType
and aDictionary<SportType, Int32>
containing the associated values. The you can simply writeval += sportTypeScoreMap[sportType]
and you are done.Variations of this pattern will help you in many similar situations.
使用 switch 语句或过滤函数。
通过过滤器功能,我的意思是:
然后应用过滤器:
请注意,使用字典过滤器效果更好,但这不是必需的。
Use either a switch statement or filter function.
By filter function, I mean something like:
Then apply the filter with:
Note that the filter works much better using a dictionary, but it is not required.
抄袭《The Pragmatic Programmer》,您可以使用 DSL 来封装规则并编写流程引擎。对于您提出的问题,解决方案可能如下所示:
然后匹配 MATCH 的第一列中的所有内容以及您遇到的每个 SWITCH 中的第一项。您可以使用您喜欢的任何语法,然后只需编写一些脚本将其填充到代码中(或使用 Xtext,因为它看起来很酷)。
Cribbing from The Pragmatic Programmer, you could use a DSL to encapsulate the rules and write a process engine. For your presented problem, a solution might look like:
Then match everything in the first col of MATCH, and the first item in each SWITCH you come to. You can make whatever syntax you feel like, then just write a bit of script to cram that into code (or use Xtext because it looks pretty cool).
这里有一些想法:
1 使用查找表:
您可以从数据库加载表。
2 使用工厂模式:
动态工厂模式很有用在代码中频繁添加新(运动)类型的情况下。此模式使用反射来防止工厂类(或任何全局配置)被更改。它允许您简单地向代码中添加一个新类。
当然,在您的情况下,使用动态工厂甚至工厂可能有点过分了。你是唯一能说清楚的人。
Here are a few ideas:
1 Use lookup tables:
You can load the table from the database.
2 Use the factory pattern:
The Dynamic Factory Pattern is useful in situations were new (sport) types are added frequently to the code. This pattern uses reflection to prevent the factory class (or any global configuration) from being changed. It allows you to simply add a new class to your code.
Of course the use of an dynamic factory, or even a factory can be overkill in your situation. You're the only one who can tell.
作为第一步,我可能会将每个逻辑处理区域分解为自己的方法:(作为第一遍可能不是最好的名称)
接下来,根据规则的复杂程度,我可能会将每个部分分解为自己的类,并且让它们由主类(如工厂)处理。
As a first step I would probably break up each logical processing area into its own method: (May not be the best names as a first pass)
Next, depending on how complex the rules are, I may break each section into its own class and have them processed by a main class (like a factory).
我没有什么特别可以提供给你的,只是首先建议不要把它当作一个大块——把它分成几个部分,在重要部分之间设置注释分隔线。
另一个建议是,如果您要像示例中那样进行许多非常短的测试,请打破惯例,将 val 增量器与求值和缩进放在同一行,以便它们彼此对齐。
过多的空白会使这数百个内容变成数百行,导致垂直滚动过多并且难以获得事物的整体视图。
I have nothing special to offer you than to first recommend not to just leave it as a big block-- break it into sections, make comment dividers between important parts.
Another suggestion is if you are going to have many very short tests as in your example, break from convention and put the val incrementors on the same line as the evaluatation and indent so they align with eachother.
Excess whitespace can make those hundred things into several hundred lines, making vertical scrolling excessive and difficult to get an overall view of the thing.
如果您真的只是以这种方式添加值,我会创建一个具有与数组中存储的值相对应的定义索引的枚举。然后你可以做这样的事情:
If you are really just adding values in this sort, I would either create an enumeration with defined indices that correspond to stored values in an array. Then you can do something like this:
考虑实现策略模式,它利用继承/多态性来使管理各个函数变得理智。通过将每个函数分离到其自己的专用类中,您可以避免拥有长达数英里的
case
块或if
语句的噩梦。不确定 C# 是否支持(或将来),但 VB.NET 集成了 XML Comment CompletionList 指令进入智能感知,当与策略模式结合使用时,它可以为您提供枚举的易用性以及面向对象的开放式可扩展性。
Consider implementing the Strategy Pattern which utilizes inheritance/polymorphism to make managing individual functions sane. By seperating each function into its own dedicated class you can forego the nightmare of having miles-long
case
blocks orif
statements.Not sure if C# supports it yet (or ever will) but VB.NET integrates XML Comment CompletionList directives into intellisense, which--when combined with the Strategy Pattern--can give you the ease of use of an Enum with the open-ended extensibility of OO.