你能不用if语句写任何算法吗?

时间:2009-12-20 22:44:31

标签: oop

这个网站勾勒出我的幽默感 - http://www.antiifcampaign.com/,但是在你使用if语句的每种情况下,多态性都可以工作吗?

18 个答案:

答案 0 :(得分:39)

回答:**该网站反对使用if语句来检查对象是否具有特定类型。这与if (foo == 5)完全不同。如果像if (foo instanceof pickle)那样使用它是不好的。替代方法是使用多态来促进封装,使代码更容易调试,维护和扩展。

一般来说,反对if(根据条件做某件事)不会给你什么。请注意这里的所有其他答案是如何做出决定的,那么真正的区别是什么呢?

对多态性背后原因的解释:

采取这种情况:

void draw(Shape s) {
    if (s instanceof Rectangle)
        //treat s as rectangle
    if (s instanceof Circle)
        //treat s as circle
}

如果您不必担心对象的特定类型,可以更好地理解对象是如何处理的。

void draw(Shape s) {
    s.draw();
}

这改变了如何将形状绘制到形状类本身的逻辑,因此我们现在可以将所有形状视为相同。这样,如果我们想要添加一种新的形状,我们所要做的就是编写类并给它一个draw方法,而不是在整个程序中修改每个条件列表。

这个想法在今天的编程中无处不在,接口的整个概念都是关于多态的。 (Shape是定义某个行为的接口,允许我们处理在我们的方法中实现Shape接口的任何类型。)动态编程语言更进一步,允许我们将支持必要操作的任何类型传递给方法。哪个看起来更好:(python样式伪代码)

def multiply(a,b):
    if (a is string and b is int):
        //repeat a b times.
    if (a is int and b is int):
        //multiply a and b

或使用多态:

def multiply(a,b):
    return a*b

您现在可以使用任何支持*运算符的2种类型,允许您将该方法用于尚未创建事件的类型。

请参阅polymorphismwhat is polymorhism on stackoverflow

答案 1 :(得分:39)

Smalltalk,被认为是一种“真正的”面向对象语言,没有“if”语句,它没有“for”语句,没有“while”语句。还有其他一些例子(比如Haskell),但这是一个很好的例子。

引用Smalltalk has no “if” statement

  

有些观众可能正在思考   这证明了他们的证据   怀疑Smalltalk很奇怪,   但是我要告诉你的是   这样:

     
    

“if”语句是面向对象语言的憎恶。

  
     

为什么呢?好吧,组成一个OO语言   类,对象和方法,以及   一个“如果”的陈述是不可避免的   那些。你不能写一个“if”   OO方式。它不应该存在。   条件执行,就像一切   否则,应该是一种方法。一种方法   什么?布尔值。

     

现在,有趣的是,在Smalltalk中,   Boolean有一个名为的方法   ifTrue:ifFalse :(该名称将显示   现在很奇怪,但是过去了   现在)。它在布尔值中是抽象的,但是   Boolean有两个子类:True和   假。该方法通过两个块   代码在True中,方法简单   运行真实案例的代码。在   错误,它运行false的代码   案件。这是一个有希望的例子   说明:

(x >= 0) ifTrue: [
'Positive'
] ifFalse: [
'Negative'
]
     

你应该能够看到ifTrue:和   ifFalse:在那里。别担心   他们不在一起。

     

表达式(x> = 0)的计算结果为   对或错。说的是真的,那么我们   有:

true ifTrue: [
'Positive'
] ifFalse: [
'Negative'
]
     

我希望这很明显   这将产生'积极'。

     

如果是假的,我们会:

false ifTrue: [
'Positive'
] ifFalse: [
'Negative'
]
     

产生'否定'。

     

好的,这就是它的完成方式。怎么回事   好极了吗?那么,在其他什么   语言可以这样做吗?更多   认真的,答案是那里   在这方面没有任何特殊情况   语言。一切都可以在一个完成   OO方式,一切都在一个完成   OO方式。

我绝对建议您阅读同一作者的整篇文章和Code is an object

答案 2 :(得分:7)

虽然不与OOP相关:在Prolog中,编写整个应用程序的唯一方法是不使用if语句。

答案 3 :(得分:6)

是的,实际上,你可以使用一种图灵完整的语言,它本身没有“if”,只允许“while”语句:

http://cseweb.ucsd.edu/classes/fa08/cse200/while.html

对于OO设计,在某些情况下使用继承模式而不是基于类型字段的开关是有意义的......但这并不总是可行或必然是可取的。

@ennuikiller:条件只是语法糖的问题:

if (test) body;     is equivalent to    x=test; while (x) {x=nil; body;}

if-then-else更加冗长:

if (test) ifBody; else elseBody;

is equivalent to

x = test; y = true;
while (x) {x = nil; y = nil; ifBody;}
while (y) {y = nil; elseBody;}

原始数据结构是列表列表。如果它们是相同长度的列表,你可以说2个标量是相等的。你可以使用头/尾运算符同时循环它们,看看它们是否停在同一点。

当然可以用宏包裹起来。

最简单的图灵完整语言可能是iota。它只包含2个符号('i'和'*')。

答案 4 :(得分:6)

“反if”运动背后的原因与Kent Beck所说的相似:

  

好的代码总是有一些小方法和   小物件。只有将系统分解为许多小块状态   和功能你能希望满足“曾经且只有一次”的规则。我得到了很多   对这个想法的抵制,特别是来自经验丰富的开发人员,但没有人   我对系统做的事情提供了尽可能多的帮助,就像把它分成更多部分一样。

如果您不知道如何使用合成和继承来计算程序,那么您的类和方法将随着时间的推移而变得更大。当您需要进行更改时,最简单的方法是在某处添加IF。添加太多的IF,您的程序将变得越来越不可维护,并且最简单的方法是添加更多的IF。

你没有 将每个IF转变为对象协作;但是当你知道如何: - )

时,这是一件非常好的事情

答案 5 :(得分:6)

是的。 if语句意味着分支在许多现代处理器上都非常昂贵 - 尤其是PowerPC。许多现代PC会进行大量的管道重新排序,因此分支误预测可能会导致每个分支未命中大约30个周期的订单。 在控制台编程时,有时执行代码并忽略它比检查是否应该执行它更快!

C中的简单分支避免:

if (++i >= 15)
{
    i = 0;
)

可以重写为

 i = (i + 1) & 15;  

然而,如果你想看到一些真正的反if,那么请阅读this

哦,在OOP问题上 - 我将用虚函数调用替换分支错误预测?不,谢谢......

答案 6 :(得分:3)

您可以使用对象(在伪python中)定义True和False:

class True:
    def if(then,else):
        return then
    def or(a):
        return True()
    def and(a):
        return a
    def not():
        return False()

class False:
    def if(then,else):
        return false
    def or(a):
        return a
    def and(a):
        return False()
    def not():
        return True()

我认为这是一种构建布尔值的优雅方式,它证明了你可以用多态来取代每一个,但这不是反if运动的重点。目标是避免编写诸如(在寻路算法中)的东西:

if type == Block or type == Player:
    # You can't pass through this
else:
    # You can

而是在每个对象上调用is_traversable方法。从某种意义上说,这正是模式匹配的逆过程。 “if”很有用,但在某些情况下,它不是最佳解决方案。

答案 7 :(得分:3)

我假设您实际上是在询问是否替换if检查类型的语句,而不是替换所有if语句。

要替换if with polymorphism,需要一个公共超类型中的方法,可以通过直接覆盖它,或者通过重用访问者模式中的重写方法来用于调度。

但是,如果没有这样的方法,并且你不能将一个添加到一个普通的超类型,因为超级类型不是你维护的呢?你是否真的会花时间引入一个新的超类型和子类型只是为了摆脱单个if?在我看来,那将是纯粹的一点。

此外,两种方法(直接覆盖和访问者模式)都有其缺点:直接覆盖方法需要在要打开的类中实现方法,这可能无助于凝聚。另一方面,如果几个案例共享相同的代码,则访问者模式很难。如果你能做到:

if (o instanceof OneType || o instanceof AnotherType) {
    // complicated logic goes here
}

您如何与访客模式共享代码?叫一个常用的方法?你会把这种方法放在哪里?

所以不,我不认为替换这样的if语句总是一种改进。它经常是,但并非总是如此。

答案 8 :(得分:2)

我曾经使用委托字典中的回调或多态来编写代码recommend in the anti-if campaign

这是一个相当诱人的论点,特别是如果你正在处理凌乱的代码库,但说实话,虽然它对于插件模型或简化大型嵌套if语句很有用,但它确实使导航和可读性有点痛苦。 / p>

例如,visual studio中的F12(转到定义)将带您进入抽象类(或者,在我的示例中为接口定义)。

它还使得对类的快速视觉扫描非常麻烦,并且增加了设置委托和查找哈希的开销。

使用反if广告系列中提出的建议,就像他们看起来推荐的那样,对我来说就是“噢,新的闪亮之物”节目。

至于在这个帖子中提出的其他结构,尽管它是以有趣的挑战的精神完成的,只是替代if语句,并没有真正解决反if的基本信念广告活动。

答案 9 :(得分:2)

如果您将业务逻辑代码中的ifs保留在构造代码(工厂,构建器,提供商等)中,则可以避免使用ifs。您的业​​务逻辑代码将更易读,更易于理解或更易于维护或扩展。请参阅:http://www.youtube.com/watch?v=4F72VULWFvc

答案 10 :(得分:1)

你可以在没有if的情况下做到这一点,但如果没有允许你根据某些条件做出决定的机制,你就无法做到。

在汇编中,没有if语句。有条件跳跃。

例如在Haskell中,没有明确的if,相反,你多次定义一个函数,我忘记了确切的语法,但它是这样的:

伪Haskell中:

def posNeg(x < 0):
    return "negative"

def posNeg(x == 0):    
    return "zero"

def posNeg(x):
    return "positive"

当您致电posNeg(a)时,解释程序会查看a的值,如果它是< 0,那么它会选择第一个定义,如果它是== 0那么它将选择第二个定义,否则它将默认为第三个定义。

因此,虽然像Haskell和SmallTalk这样的语言没有通常的C风格if语句,但他们还有其他方法可以让你做出决定。

答案 11 :(得分:1)

这实际上是我喜欢用编程语言编写的编码游戏。它被称为“如果我们没有if”,其起源于:http://wiki.tcl.tk/4821

基本上,如果我们不允许在语言中使用条件结构:no if,no while,no for,no除非没有开关等。我们可以重新创建自己的IF函数。答案取决于语言以及我们可以利用的语言特征(记住使用常规条件结构会欺骗三元运算符!)

例如,在tcl中,函数名只是一个字符串,任何字符串(包括空字符串)都允许任何内容(函数名,变量名等)。所以,利用这个,我们可以做到:

proc 0 {true false} {uplevel 1 $false; # execute false code block, ignore true}
proc 1 {true false} {uplevel 1 $true;  # execute true code block, ignore flase}

proc _IF {boolean true false} {
    $boolean $true $false
}

#usage:
_IF [expr {1<2}] {
    puts "this is true"
} {
  #else:
    puts "this is false"
}

或者在javascript中我们可以滥用松散的输入以及几乎任何东西都可以转换为字符串并将其与其功能性结合起来的事实:

function fail (discard,execute) {execute()}
function pass (execute,discard) {execute()}
var truth_table = {
    'false' : fail,
    'true' : pass
}
function _IF (expr) {
  return truth_table[!!expr];
}

//usage:
_IF(3==2)(
    function(){alert('this is true')},
//else
    function(){alert('this is false')}
);

并非所有语言都能做到这一点。但我喜欢的语言往往能够。

答案 12 :(得分:1)

Haskell甚至没有if语句,纯粹是功能性的。 ; d

答案 13 :(得分:0)

这取决于语言。

静态类型语言应该能够通过共享公共接口和重载函数/方法来处理所有类型检查。

动态类型语言可能需要以不同方式处理问题,因为传递消息时不会检查类型,仅在访问对象时(或多或少)。使用通用接口仍然是很好的做法,并且可以消除许多类型检查if语句。

虽然有些构造通常是代码嗅觉的标志,但我对于消除apriori问题的任何方法都犹豫不决。有时候类型检查是否是权宜之计。

注意:其他人建议使用开关代替,但这只是一种写出更易读的if语句的聪明方法。

答案 14 :(得分:0)

多态的想法是在不首先验证该对象的类的情况下调用对象 这并不意味着不应该使用if语句;你应该避免写

if (object.isArray()) {
  // Code to execute when the object is an array.
} else if (object.inString()) {
  // Code to execute if the object is a string.
}

答案 15 :(得分:0)

好吧,如果你用Perl写作,那很简单!

而不是

if (x) {
    # ...
}

你可以使用

unless (!x){
    # ... 
}

- )

答案 16 :(得分:0)

在回答问题时,正如上一位受访者所建议的,你需要一些if语句来检测工厂中的状态。然后,您将实例化一组解决状态特定问题的协作类。当然,根据需要还需要其他条件,但它们会被最小化。

当然要删除的是在如此多的基于服务的代码中无休止的程序状态检查。

提到有趣的smalltalk,因为这是我在被拖入Java之前使用的语言。我不像以前那样早点回家。

答案 17 :(得分:0)

我考虑过添加两分钱:你可以在许多语言中优化ifs,其中布尔表达式的第二部分在不影响结果时不会被评估。

使用and运算符,如果第一个操作数的计算结果为false,则无需计算第二个操作数。对于or运算符,情况正好相反 - 如果第一个操作数为true,则无需计算第二个操作数。有些语言总是这样,其他语言提供了另一种语法。

这是一个if - elseif - 用JavaScript编写的代码,仅使用运算符和匿名函数。

document.getElementById("myinput").addEventListener("change", function(e) {

  (e.target.value == 1 && !function() {
    alert('if 1');
  }()) || (e.target.value == 2 && !function() {
    alert('else if 2');
  }()) || (e.target.value == 3 && !function() {
    alert('else if 3');
  }()) || (function() {
    alert('else');
  }());

});
<input type="text" id="myinput" />

这让我想尝试定义一种深奥的语言,其中块隐式表现得像自执行匿名函数并返回true,因此你可以像这样编写它:

(condition && {
  action
}) || (condition && {
  action
}) || {
  action
}