if-less 编程(基本上没有条件)[关闭]

Posted

技术标签:

【中文标题】if-less 编程(基本上没有条件)[关闭]【英文标题】:If-less programming (basically without conditionals) [closed] 【发布时间】:2011-11-08 00:19:07 【问题描述】:

我有一位同事告诉我,他曾经在一家公司工作,该公司的政策是在代码中永远不要有条件(“if”和“switch”语句),并且他们让代码中的所有决定使用多态性和(我猜)其他一些 OO 原则来完成。

有点理解这背后的原因,即拥有更干燥且更容易更新的代码,但我正在寻找对这个概念的更深入的解释。或者,它可能是更通用的设计方法的一部分。

如果有人对此有任何资源,或者愿意解释,甚至有更多与此相关的术语,我可以用它来找到更多答案,我将非常感激。

我发现 one question on SO 有点相关,但我不熟悉 C++,所以我不太了解那里的答案。

(顺便说一句,我不是 OO 大师,但我可以做到)

我最精通 php,然后是 Python,所以我更喜欢使用这些语言的信息。

更新:我会向我的同事询问更多信息,了解他的确切含义。

2015 年更新:经过多年的编程经验,我现在看到,这项政策的目的可能是防止程序员通过在某些地方添加条件(if 语句)以随意的方式添加功能。扩展软件的更好方法是使用"Open/Closed principle",其中通过使用继承和多态来扩展软件。我强烈怀疑该政策是否对所有条件都非常严格,因为没有它们很难完全做到。

【问题讨论】:

你同事所说的这家公司是什么?我问这样我可以避开他们。流控制语句是编程的基础。如果我什至不能使用最基本的工具在适当的时候完成工作,还有什么我不能使用的?是的,您确实可以滥用if 语句,但对于其他一切都是如此。 @In silico - 流控制语句是过程编程的基础。多态性是面向对象编程的基础。也就是说,我们大多数人都使用这两种范式。 @TrueWill:流控制是命令式编程的基础,OOP 与过程式编程一样基于命令式编程。即使你去“纯”OOP,你仍然有同样的东西包裹在稍微更 OOP-y 的衣服中(condition ifTrue,正如 Smalltalk 所做的那样,与if condition 具有基本相同的效果和含义)。而且您必须对多态性使用一些流控制,除非您想将所有内容(例如整数的偶数)包装到专用对象中。 Can you write any algorithm without an if statement?的可能重复 多态性在很大程度上依赖于重载,所以对于像 js 和 php 这样的语言你注定要使用这种方法。 【参考方案1】:

Anti-IF Campaign网站上有一些资源,比如this article。

我相信这是一个程度的问题。条件并不总是不好,但它们可能(并且经常)被滥用。

其他想法(一天后)

Refactoring: Improving the Design of Existing Code 是关于这个主题(以及许多其他主题)的一个很好的参考。它涵盖Replace Conditional with Polymorphism。网站上还有一个新的 Replace Conditional with Visitor。

我看重简单性和single responsibility,而不是删除所有if 语句。这三个目标通常是一致的。支持cyclomatic complexity 指标的静态分析工具可以快速指出带有嵌套或串行条件的代码。 if 语句可能会保留在重构后,但可以分解为更小的方法和/或多个类。

更新:Michael Feathers 在Unconditional Programming 上写了一篇文章。

这是一个热门话题:Phil Haack on Death to the IF statement!

【讨论】:

我认为包含 Google Tech Talks 中讨论这一原则的视频也很重要:youtube.com/watch?v=4F72VULWFvc【参考方案2】:

我有个同事告诉我他曾经在一家公司工作 作为一项政策,永远不要有条件(“if”和“switch” 语句)在代码中,他们让所有的决定在 使用多态性和(我猜)其他一些 OO 来完成代码 原则。

我认为您的同事误解了某些内容或使用了错误的词语来解释它。 而且你不能完全避免条件语句。

有句话要说:OOP 中 if 语句的激增可能是糟糕编程的征兆。一些例子:

不要像旧的 C 风格编程那样使用 if 来检查函数的返回值:

int ret = some_func();
if (ret != null)
   //do something

这在 C 代码中很典型,但对于 OOP,您应该使用异常:

try
    do_something();
catch(Exception e)
    e.printStackTrace(); //why I was not able to do something
    handle(e); //there is something else I could do to handle the occurred error

有时 if 语句的扩散与糟糕的设计有关。考虑下面的 Java 示例:

BaseClass base;
if (base instanceof DerivedClassOneFromBase)
    DerivedClassOneFromBase d = (DerivedClassOneFromBase)base;
    d.methodOne();
else if (base instanceof DerivedClassOneFromBase)
    DerivedClassTwoFromBase d = (DerivedClassTwoFromBase)base;
    d.methodTwo();

这是另一个糟糕的 if 语句示例,可能与糟糕的设计有关。如果这两个派生对象在它们的基类 BaseClass 中定义了一个公共方法,那么您可以调用该方法而不是检查它们的具体类型并进行强制转换:

base.commonMethod();

【讨论】:

我也同意,如果在应用程序内部是一个糟糕的 symoton!但是使用 try catch 作为流决策结构更糟糕,1. 你使用 if/else 的方式相同 2. 它太慢了(自我体验!!!)。 ps;我并不是说你上面的代码是好是坏,因为它与任何上下文都是隔离的。 @Renato - 正如你所说,这是关于上下文的。 Microsoft 建议使用异常来报告错误/失败,而不是返回值。 Framework Design Guidelines 有一个章节。 @Renato Gama:是的,异常稍微慢一些,但关键是它们是异常。他们不应该控制流程决策结构,而是处理偶尔的错误。 顺便说一句,异常与 OOP 是正交的,尽管我想不出任何缺少它的 OOP 语言(除了 Go,它只是一种 OO。)【参考方案3】:

我阅读了您链接的帖子,似乎他们主要是在谈论消除类中对条件的需求,不要与所有代码混淆。这个想法是,如果您需要检查一个对象的状态(使用条件)以确定它是否具有某些功能,那么实际上您有两个对象(一个支持该功能,一个不支持该功能)并且应该将它们定义为两个相关的类。

【讨论】:

【参考方案4】:

有时方法中的条件是不好的,因为它们表明您只是在一个方法中执行多个功能或多种类型的方法。

如果您有一个名为汽车的类和子类(例如 Car 和 Bike),以及一个方法,例如:

drive(Automobile a)
   if (a.isCar)
      // do stuff
   else if (a.isBike)
      // do stuff

你很可能做错了什么。即使它不是基于类型的开关,它也经常是错误的。如果该方法根据某个变量执行多个功能,则它通常会尝试做不止一件事,并且可能应该分成多个方法。

例如:

save(Car c)
   if (c is new)
      // do some stuff
   else if (c is old)
      // do some stuff

可能会分为保存和更新,因为它们是两个不同的功能。虽然它确实取决于。

完全禁止 if 语句会很愚蠢,因为它们有很多有效的用例。

【讨论】:

【参考方案5】:

经过几年的编程,我回到了我自己的问题,我现在对它的上下文有了更好的理解。

Sandi Metz 进行了一场精彩的演讲,她将一个非常多毛的 if 语句重构为一些毛茸茸的东西:https://www.youtube.com/watch?v=8bZh5LMaSmE

【讨论】:

【参考方案6】:

避免条件并不一定意味着您需要通过多态性或继承来完成它,例如:

您有 3 个不同的文件夹来存储上传的图片、上传的视频和上传的 pdf

你可以这样写代码:

uploadMedia(mediaType)
   if(mediaType == images)
     uploadTo("myProject/images");
   else if(mediaType == videos)
     upoloadTo("myProject/videos);  
   else if(mediaType == pdf)
     uploadTo("myProject/pdf");
  

人们可能使用的另一种选择是 switch-case:

uploadMedia(mediaType)
         switch(mediaType)
         case : images
         uploadTo("myProject/images");
         break;

         case : videos
         uploadTo("myProject/videos");
         break;

         case : pdf
         uploadTo("myProject/pdf");
         break;
    

但是你可以通过使用字典/哈希图/json之类的东西来完全避免条件语句(取决于你使用的任何东西):

例如:

HashMap<String,String> mediaMap = new HashMap<>();

mediaMap.put("images","myProject/images");
mediaMap.put("videos","myProject/videos");
mediaMap.put("pdf","myProject/pdf");

//mediaType can be images/videos/pdf same as keys of mediaMap
uploadMedia(mediaType)
  uploadTo(mediaMap.get(mediaType));

这是一种伪代码,因此可能存在语法错误,但总体而言,这个概念也有助于避免条件。也可以减少代码行数。

【讨论】:

Switch 语句只是用其他词编写的 if 语句,也称为“语法糖”,所以这并不能真正回答我的问题。 hashmap 基本上是另一种编写 switch 语句的方式。 if-less 编程(据我所知)更多的是避免在使用 if 语句(很多)时(很可能)会遇到的问题。它们往往会成倍增加并使代码难以阅读。如果您使用开放/封闭原则或继承,您可以避免这种情况(当然也会遇到其他问题)。 我没有得到你的这部分评论hashmap 基本上是另一种编写switch 语句的方式。我认为它可以替代 switch-case 和 if-else,使代码更易于阅读。此外,如果您或阅读本文的任何人可以告诉我在 if/else 或 switch/case 上使用 hashmap 的性能效果,它真的会帮助我理解。这也可以帮助我了解性能瓶颈。谢谢:) 你是对的,使用 hashmap 可以替代 switch-case 和 if-else 语句。这是一种有时可以使代码更易于阅读的替代方法。如果您正在寻找非条件的东西,这不是一种选择。只是写的不一样。如果您想发现一种编程解决方案相对于另一种的性能影响,您可以简单地使用计时器对其进行测量。但是我们不要在这个线程中跑题:-) 谢谢,你说得对,不应该在这个线程上跑题?

以上是关于if-less 编程(基本上没有条件)[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

无需硬件即可进行 CUDA 编程的 GPU 模拟器 [关闭]

最好的基于编程的游戏[关闭]

哪些编程语言不被视为高级语言? [关闭]

对数据库编程的基本理解[关闭]

使用 JavaScript 以编程方式编写 html [关闭]

sass用法