Vad*_*dim 64 programming-languages if-statement
我刚刚参加了简单设计和测试会议.在其中一个会话中,我们讨论的是编程语言中的邪恶关键词. 科瑞海恩斯,谁提出的问题,确信if说法是绝对的邪恶.他的另一种选择是用谓词创建函数.你能告诉我为什么if是邪恶的.
我知道你可以编写非常难看的代码滥用if.但我不相信它那么糟糕.
fly*_*ire 84
还有另一种if可能是邪恶的感觉:当它来源而不是多态性时.
例如
if (animal.isFrog()) croak(animal)
else if (animal.isDog()) bark(animal)
else if (animal.isLion()) roar(animal)
Run Code Online (Sandbox Code Playgroud)
代替
animal.emitSound()
Run Code Online (Sandbox Code Playgroud)
但基本上,如果它是一个完全可以接受的工具.它当然可以被滥用和滥用,但它远不及goto的地位.
Gro*_*roo 77
条件子句有时会导致代码更难管理.这不仅包括if语句,更常见的是switch语句,它通常包括比相应的更多的分支if.
if当您编写实用程序方法,扩展或特定库函数时,您可能无法避免ifs(并且您不应该).没有更好的方法来编写这个小函数,也没有比它更自我记录:
// this is a good "if" use-case
int Min(int a, int b)
{
if (a < b)
return a;
else
return b;
}
// or, if you prefer the ternary operator
int Min(int a, int b)
{
return (a < b) ? a : b;
}
Run Code Online (Sandbox Code Playgroud)
另一方面,如果您遇到测试某种类型代码的代码,或者测试变量是否属于某种类型,那么这很可能是重构的良好候选者,即用多态替换条件.
这样做的原因是,通过允许您的调用者对某个类型代码进行分支,您可能会在代码中分散大量检查,从而使扩展和维护变得更加复杂.另一方面,多态性允许您将此分支决策尽可能地更接近程序的根.
考虑:
// this is called branching on a "type code",
// and screams for refactoring
void RunVehicle(Vehicle vehicle)
{
// how the hell do I even test this?
if (vehicle.Type == CAR)
Drive(vehicle);
else if (vehicle.Type == PLANE)
Fly(vehicle);
else
Sail(vehicle);
}
Run Code Online (Sandbox Code Playgroud)
通过将常见但特定于类型(即特定于类)的功能放入单独的类并通过虚拟方法(或接口)公开它,您允许程序的内部部分将此决策委派给调用层次结构中较高的人(可能在代码中的单个位置),允许更容易的测试(模拟),可扩展性和维护:
// adding a new vehicle is gonna be a piece of cake
interface IVehicle
{
void Run();
}
// your method now doesn't care about which vehicle
// it got as a parameter
void RunVehicle(IVehicle vehicle)
{
vehicle.Run();
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以轻松测试您的RunVehicle方法是否正常工作:
// you can now create test (mock) implementations
// since you're passing it as an interface
var mock = new Mock<IVehicle>();
// run the client method
something.RunVehicle(mock.Object);
// check if Run() was invoked
mock.Verify(m => m.Run(), Times.Once());
Run Code Online (Sandbox Code Playgroud)
if条件上不同的模式可以重复使用关于if在你的问题中用"谓词" 替换的论点,Haines可能想要提到有时候你的代码中存在类似的模式,这些模式仅在条件表达式上有所不同.条件表达式与ifs 一起出现,但整个想法是将重复模式提取到单独的方法中,将表达式作为参数.这就是LINQ已经做过的事情,与其他选择相比,通常会产生更清晰的代码foreach:
考虑这两个非常相似的方法:
// average male age
public double AverageMaleAge(List<Person> people)
{
double sum = 0.0;
int count = 0;
foreach (var person in people)
{
if (person.Gender == Gender.Male)
{
sum += person.Age;
count++;
}
}
return sum / count; // not checking for zero div. for simplicity
}
// average female age
public double AverageFemaleAge(List<Person> people)
{
double sum = 0.0;
int count = 0;
foreach (var person in people)
{
if (person.Gender == Gender.Female) // <-- only the expression
{ // is different
sum += person.Age;
count++;
}
}
return sum / count;
}
Run Code Online (Sandbox Code Playgroud)
这表明您可以将条件提取到谓词中,为这两种情况(以及许多其他未来情况)留下一种方法:
// average age for all people matched by the predicate
public double AverageAge(List<Person> people, Predicate<Person> match)
{
double sum = 0.0;
int count = 0;
foreach (var person in people)
{
if (match(person)) // <-- the decision to match
{ // is now delegated to callers
sum += person.Age;
count++;
}
}
return sum / count;
}
var males = AverageAge(people, p => p.Gender == Gender.Male);
var females = AverageAge(people, p => p.Gender == Gender.Female);
Run Code Online (Sandbox Code Playgroud)
而且由于LINQ已经有了许多方便的扩展方法,你实际上甚至不需要编写自己的方法:
// replace everything we've written above with these two lines
var males = list.Where(p => p.Gender == Gender.Male).Average(p => p.Age);
var females = list.Where(p => p.Gender == Gender.Female).Average(p => p.Age);
Run Code Online (Sandbox Code Playgroud)
在最后一个LINQ版本中,if语句完全"消失",但是:
if本身并不存在,而是整个代码模式(仅仅因为它是重复的),而且if实际上仍然存在,但它是在LINQ Where扩展方法中编写的,该方法已经过测试并关闭以进行修改.拥有较少的自己的代码总是一件好事:要测试的东西少,出错的东西少,代码更容易遵循,分析和维护.说完这一切之后,你不应该因为现在和那里有几个条件而度过不眠之夜.虽然这些答案可以提供一些一般的经验法则,但能够检测需要重构的构造的最佳方法是通过经验.随着时间的推移,出现了一些模式,导致一遍又一遍地修改相同的条款.
Jor*_*mer 32
Code Complete的一句好话:
代码就好像维护你的程序的人是一个知道你住在哪里的暴力精神病患者.
- 匿名
我保持简单.如果通过在特定区域中使用谓词来增强应用程序的可读性,请使用它.否则,使用'if'并继续前进.
Kyl*_*ndo 17
我认为这取决于你所做的事实.
如果你有一个简单的if..else陈述,为什么要使用predicate?
如果可以,可以使用switch更大的if替换,然后如果选择将谓词用于大型操作(有意义的话,否则您的代码将成为维护的噩梦),请使用它.
这个家伙似乎对我的喜欢有点迂腐.if用Predicates 取代所有的东西只是疯狂的谈话.
Kei*_*oom 14
今年早些时候开始的Anti-If活动.主要前提是许多嵌套的if语句通常可以用多态替换.
我很想看到使用Predicate的例子.这更像功能编程吗?
就像关于金钱的圣经经文一样,如果陈述不是邪恶的 - 那么陈述的爱就是邪恶的.没有if语句的程序是一个荒谬的想法,必要时使用它们是必不可少的.但是一个程序有100个if-else if连续的块(遗憾的是,我已经看到了)绝对是邪恶的.
我不得不说,我最近已经开始将陈述视为代码气味:特别是当你发现自己多次重复相同的情况时.但是你需要了解一些关于代码味道的东西:它们并不一定意味着代码很糟糕.他们只是说,有一个很好的机会的代码是坏的.
例如,评论被Martin Fowler列为代码气味,但我不会认真对待任何人说"评论是邪恶的;不要使用它们".
但一般来说,我更喜欢使用多态而不是if语句.这只会减少错误的空间.我倾向于发现很多时候,使用条件也会导致很多tramp参数(因为你必须将形成条件所需的数据传递给适当的方法).
谓词来自逻辑/声明性编程语言,例如 PROLOG。对于某些类别的问题,比如约束求解,它们可以说比许多冗长的、逐步的“如果-这个-做-那么-那么-做-这个”废话要好。在命令式语言中解决起来冗长而复杂的问题在 PROLOG 中只需几行即可完成。
还有可扩展编程的问题(由于向多核、网络等的发展)。一般来说,if 语句和命令式编程往往是按步骤顺序进行的,并且不可扩展。然而,逻辑声明和 lambda 演算描述了如何解决问题以及可以将其分解为哪些部分。因此,执行该代码的解释器/处理器可以有效地将代码分解为多个片段,并将其分布在多个 CPU/核心/线程/服务器上。
绝对不是到处都有用;我不想尝试使用谓词而不是 if 语句编写设备驱动程序。但是,是的,我认为要点可能是合理的,并且至少值得熟悉,即使不是一直使用。