C# 大型开关语句:糟糕的OOP?
我一直认为,大型switch语句是糟糕的OOP设计的征兆。在过去,我读过讨论这个主题的文章,他们提供了基于面向对象的替代方法,通常基于多态性来实例化正确的对象来处理这个问题 我现在遇到的情况是,有一个基于TCP套接字的数据流的怪异的switch语句,协议基本上由换行终止的命令组成,后面是数据行,后面是结束标记。该命令可以是100个不同命令中的一个,因此我想找到一种方法,将这个monster switch语句简化为更易于管理的语句 我在谷歌上搜索了一些我记得的解决方案,但遗憾的是,谷歌现在已经变成了一片荒原,因为很多种查询都没有相关的结果 这类问题有什么模式吗?对可能的实施有什么建议吗 我的一个想法是使用字典查找,将命令文本与要实例化的对象类型相匹配。这样做的好处是,只需创建一个新对象,并在表中为任何新命令插入一个新命令/类型 然而,这也存在类型爆炸的问题。我现在需要100个新类,另外我还必须找到一种方法将它们干净地连接到数据模型。“一个真正的开关声明”真的是一条路吗C# 大型开关语句:糟糕的OOP?,c#,oop,design-patterns,C#,Oop,Design Patterns,我一直认为,大型switch语句是糟糕的OOP设计的征兆。在过去,我读过讨论这个主题的文章,他们提供了基于面向对象的替代方法,通常基于多态性来实例化正确的对象来处理这个问题 我现在遇到的情况是,有一个基于TCP套接字的数据流的怪异的switch语句,协议基本上由换行终止的命令组成,后面是数据行,后面是结束标记。该命令可以是100个不同命令中的一个,因此我想找到一种方法,将这个monster switch语句简化为更易于管理的语句 我在谷歌上搜索了一些我记得的解决方案,但遗憾的是,谷歌现在已经变成
我非常感谢您的想法、意见或评论。我认为您可以改进的一种方法是让您的代码由数据驱动,因此,例如,对于每个代码,您可以匹配处理它的内容(函数、对象)。您还可以使用反射来映射表示对象/函数的字符串,并在运行时解析它们,但您可能需要进行一些实验来评估性能。我看到了策略模式。如果我有100种不同的策略…就这样吧。巨型交换机的声明是丑陋的。所有命令都是有效的类名吗?如果是这样,只需使用命令名作为类名,并使用Activator.CreateInstance创建strategy对象。您可能会从中获得一些好处 对于OOP,如果行为变化足够小的话,您可以将几个类似的命令折叠成一个类,以避免完全的类爆炸(是的,我已经听到OOP大师对此尖叫了)。但是,如果系统已经是OOP,并且100多个命令中的每一个都是真正唯一的,那么只需将它们设置为唯一的类,并利用继承来整合公共内容
如果系统不是OOP,那么我不会仅仅为此添加OOP。。。您可以通过简单的字典查找和函数指针轻松地使用命令模式,甚至可以根据命令名动态生成函数调用,具体取决于语言。然后,您可以将逻辑关联的函数分组到表示类似命令集合的库中,以实现可管理的分离。我不知道是否有一个好的术语来描述这种实现。。。我一直认为它是一种“调度程序”风格,基于处理URL的MVC方法。我认为这是少数几种情况之一,大型交换机是最好的解决方案,除非出现其他解决方案。我认为有两个交换机语句是非面向对象设计的症状,其中,打开枚举类型的开关可能被提供抽象接口的不同实现的多个类型所取代;例如,下面的
switch (eFoo)
{
case Foo.This:
eatThis();
break;
case Foo.That:
eatThat();
break;
}
switch (eFoo)
{
case Foo.This:
drinkThis();
break;
case Foo.That:
drinkThat();
break;
}
。。。也许应该改写为
IAbstract
{
void eat();
void drink();
}
class This : IAbstract
{
void eat() { ... }
void drink() { ... }
}
class That : IAbstract
{
void eat() { ... }
void drink() { ... }
}
然而,一个switch语句并不是一个强有力的指示器,表明switch语句应该被其他语句替换。处理这个特定问题的最佳方法:干净地序列化和协议是使用IDL并用switch语句生成封送代码。因为无论您尝试使用什么模式(原型工厂、命令模式等),您都需要初始化命令id/字符串和类/函数指针之间的映射,而且它的运行速度比switch语句慢,因为编译器可以对switch语句使用完美的哈希查找 该命令可以是100个不同命令中的一个 如果你需要做100件不同事情中的一件,你不能避免有一个100路分支。您可以在控制流(开关,如果elseif^100)或数据(从字符串到命令/工厂/策略的100元素映射)中对其进行编码。但它会在那里
您可以尝试将100路分支的结果与不需要知道该结果的内容隔离开来。也许100种不同的方法就可以了;如果这会使代码变得笨拙,那么就没有必要发明你不需要的对象。是的,我认为大箱语句是代码可以改进的征兆。。。通常通过实现更面向对象的方法。例如,如果我发现自己在一个switch语句中评估类的类型,这几乎总是意味着我可以使用泛型来消除switch语句。您也可以在这里采用语言方法,用语法中的关联数据定义命令。然后,您可以使用生成器工具来解析该语言。我已经用过了。或者,您可以使用解释器模式
在我看来,目标不是构建最纯粹的OO模型,而是创建一个灵活、可扩展、可维护和强大的系统 我想说,问题不在于big switch语句,而在于它所包含的代码的泛滥,以及滥用范围错误的变量 我自己在一个项目中也经历过这种情况,当时越来越多的代码进入交换机,直到无法维护。我的解决方案是定义一个参数类,该类包含命令的上下文(名称、参数等,在切换之前收集),为每个case语句创建一个方法,并调用met
switch(id)
case 1: DoSomething(url_1) break;
case 2: DoSomething(url_2) break;
..
..
case 100 DoSomething(url_100) break;
string url = GetUrl(id);
DoSomthing(url);