从架构上来说,我应该如何用更易于管理的东西替换一个非常大的 switch 语句? [英] Architecturally speaking, how should I replace an extremely large switch statement with something more manageable?
问题描述
EDIT 1:忘记添加嵌套属性曲线球.
EDIT 1: Forgot to add the nested property curve ball.
更新:我选择了@mtazva 的答案,因为这是针对我的具体情况的首选解决方案.回想起来,我用一个非常具体的例子问了一个一般性的问题,我相信这最终让每个人(或者可能只是我)对问题的确切含义感到困惑.我确实相信一般问题也已得到解答(请参阅策略模式答案和链接).谢谢大家!
UPDATE: I have chosen @mtazva's answer as that was the preferred solution for my specific case. In retrospect, I asked a general question with a very specific example and I believe that ended up confusing everyone (or maybe just me) as to what the question was exactly. I do believe the general question has been answered as well (see the Strategy pattern answers and links). Thanks everyone!
大型 switch 语句显然 smell 我已经看到了一些关于如何执行此操作的链接使用映射到函数的字典.但我想知道是否有更好(或更聪明的方法)来做到这一点?在某种程度上,这是一个我一直在脑后盘旋的问题,但从来没有真正有好的解决方案.
Large switch statements obviously smell and I have seen some links on how you could do this with a dictionary that maps to functions. But I'm wondering if there is a better (or smarter way) to do this? In a way, this is a question I've always sort of had rolling around in the back of my head but never really had a good solution to.
这个问题源于我之前问的另一个问题:如何使用 C# 在 .Net 中的类型对象列表中选择对象属性的所有值
This question stemmed from another question I asked earlier: How to select all the values of an object's property on a list of typed objects in .Net with C#
这是我正在使用的示例类(来自外部来源):
Here is an example class I'm working with (from an external source):
public class NestedGameInfoObject
{
public string NestedName { get; set; }
public int NestedIntValue { get; set; }
public decimal NestedDecimalValue { get; set; }
}
public class GameInfo
{
public int UserId { get; set; }
public int MatchesWon { get; set; }
public long BulletsFired { get; set; }
public string LastLevelVisited { get; set; }
public NestedGameInfoObject SuperCoolNestedGameInfo { get; set; }
// thousands more of these
}
不幸的是,这是来自外部来源......想象一下来自侠盗猎车手或其他东西的巨大数据转储.
Unfortunately, this is coming from an external source... imagine a HUGE data dump from Grand Theft Auto or something.
我只想得到这些对象列表的一小部分.想象一下,我们希望能够将您与一群朋友的游戏信息对象进行比较.一个用户的单个结果如下所示:
And I want to get just a small cross section of a list of these objects. Imagine we want to be able to compare you with a bunch of your friends' game info objects. An individual result for one user would look like this:
public class MyResult
{
public int UserId { get; set; } // user id from above object
public string ResultValue { get; set; } // one of the value fields from above with .ToString() executed on it
}
还有一个我想用更易于管理的东西替换的例子(相信我,我不想维护这个怪物 switch 语句):
And an example of what I want to replace with something more manageable (believe me, I DON'T want to be maintaining this monster switch statement):
const int MATCHES_WON = 1;
const int BULLETS_FIRED = 2;
const int NESTED_INT = 3;
public static List<MyResult> GetMyResult(GameInfo[] gameInfos, int input)
{
var output = new List<MyResult>();
switch(input)
{
case MATCHES_WON:
output = gameInfos.Select(x => new MyResult()
{
UserId = x.UserId,
ResultValue = x.MatchesWon.ToString()
}).ToList<MyResult>();
break;
case BULLETS_FIRED:
output = gameInfos.Select(x => new MyResult()
{
UserId = x.UserId,
ResultValue = x.BulletsFired.ToString()
}).ToList<MyResult>();
break;
case NESTED_INT:
output = gameInfos.Select(x => new MyResult()
{
UserId = x.UserId,
ResultValue = x.SuperCoolNestedGameInfo.NestedIntValue.ToString()
}).ToList<MyResult>();
break;
// ad nauseum
}
return output;
}
那么问题是有没有什么合理的方法来管理这头野兽?我真正想要的是一种动态方式来获取此信息,以防初始对象发生更改(例如,添加了更多游戏信息属性).有没有更好的方法来构建它,使其不那么笨拙?
So the question is are there any reasonable ways to manage this beast? What I'd really like is a dynamic way to get this info in case that initial object changes (more game info properties are added, for instance). Is there a better way to architect this so it's less clumsy?
推荐答案
我认为你的第一句话没有找到最合理的解决方案:某种形式的字典将值映射到方法.
I think your first sentence eluded to what is probably the most reasonable solution: some form of dictionary mapping values to methods.
例如,您可以定义一个静态Dictionary
,其中每个值(例如 MATCHES_WON)都将添加一个相应的 lambda,以提取适当的值(假设您的常量等定义如您的示例所示):
For example, you could define a static Dictionary<int, func<GameInfo, string>>
, where each value such as MATCHES_WON would be added with a corresponding lambda that extracts the appropriate value (assuming your constants, etc are defined as shown in your example):
private static Dictionary<int, Func<GameInfo, string>> valueExtractors =
new Dictionary<int, Func<GameInfo, string>>() {
{MATCHES_WON, gi => gi.MatchesWon.ToString()},
{BULLETS_FIRED, gi => gi.BulletsFired.ToString()},
//.... etc for all value extractions
};
然后您可以使用此字典来提取示例方法中的值:
You can then use this dictionary to extract the value in your sample method:
public static List<MyResult> GetMyResult(GameInfo[] gameInfos, int input)
{
return gameInfo.Select(gi => new MyResult()
{
UserId = gi.UserId,
ResultValue = valueExtractors[input](gi)
}).ToList<MyResult>();
}
在此选项之外,您可能会使用数字和属性名称进行某种文件/数据库/存储查找,然后使用反射来提取值,但显然效果不佳.
Outside of this option, you could potentially have some sort of file/database/stored lookup with the number and the property name, then use reflection to extract the value, but that would obviously not perform as well.
这篇关于从架构上来说,我应该如何用更易于管理的东西替换一个非常大的 switch 语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!