【问题标题】:Do One Thing - How far to take this rule?做一件事——这条规则能走多远?
【发布时间】:2009-08-27 14:03:51
【问题描述】:

所以在“清洁代码”一书中有“做一件事”的规则。 但是我们真的要走多远。

例如以下语句:

Settings.Default.BaudRate = baudRate;
Settings.Default.COMPort = port;
Settings.Default.DataBits = dataBits;
Settings.Default.Handshake = handshake;
Settings.Default.Parity = parity;
Settings.Default.ReadTimeout = readTimeout;
Settings.Default.WriteTimeout = writeTimeout;
Settings.Default.CommunicationTimeout = communicationTimeout;
Settings.Default.Save(); 

好的,这里肯定不止一个声明, 但我确实觉得他们只是在做一件事。 保存设置。

我在一个函数中有这个。你真的会接受这间公寓吗 并且每个设置都有一个方法?

你什么时候遵守这条规则,什么时候不遵守?

【问题讨论】:

  • 如果这些是属性,那么您基本上对每个属性都有不同的方法,对吧?我不是 C# 人,但那些看起来像道具。
  • 谢谢大家的回复:-)

标签: c# coding-style


【解决方案1】:

本书的下一部分,每个函数的一个抽象层,对回答这个问题大有帮助。所有这些语句都处于同一抽象级别,因此该函数已经在做一件事,即保存设置。

【讨论】:

  • 仍然需要到达那部分:p
【解决方案2】:

对我来说看起来完全有效。该代码的明显方法名称是SaveSettings,这表明该方法只做一件事。没什么好担心的。

【讨论】:

  • 或 saveSettings 取决于编码风格。不过这个答案很完美。
【解决方案3】:

我会将它们全部放在一个 SaveSettings() 函数中——如果将它们分别放在各自的函数中,你仍然需要从另一个函数中调用所有这些函数。

【讨论】:

    【解决方案4】:

    是的,每个方法都应该只做一个的事情。但那是什么?

    这取决于您的方法所在的抽象级别。用于保存单个设置的方法(属性)是相当低的抽象。下一个更高的抽象将是建议的SaveSettings 方法。

    在顶部您有一个方法/函数main,它也只做一件事:整个程序...

    【讨论】:

      【解决方案5】:

      我没有读过那本书,但是关于这个概念......

      “一件事”并不意味着“一行代码”。 “一件事”意味着函数中的所有内容都应该在逻辑上相关。

      我会与之前的一些海报争辩说“saveSettings”是“一件事”。也许这只是措辞上的粗心,但我会借此机会指出潜在的陷阱。在您的情况下,它更像是“saveCommunicationSettings”,我认为它很容易符合“一件事”的定义。如果您将“Settings.Default.customerLoyaltyDiscount= ...”添加到该列表中,我会说您可能处于危险境地,因为您现在将通信设置与定价计算设置混合在一起。

      在现实生活中,决定什么是合理的凝聚力不是一个公式,而是一个需要运用智慧的判断。计算订单总额的函数是否应该包括销售税计算?可以说这是两件事:订单上所有商品的总价格和计算销售税。但是您也可以争辩说它只是一个:找到订单的总价格,无论涉及什么。在实践中,我经常根据逻辑的复杂性做出决定。如果计算订单总额所需的只是一个简单的循环,将所有项目的价格相加,然后从表中获取销售税率并乘以,我可能会在一个函数中完成所有操作。如果还有比这更多的东西——比如我现在正在使用的系统,计算定价涉及库存与定制订单、查找各种可能的折扣、添加保修等等——我们真的需要打破它起来。

      【讨论】:

        【解决方案6】:

        我假设这条规则引用了何时将一个函数划分为多个子函数。

        您的想法是正确的 - 保存设置是“一件事”,并且可以在它自己的功能中。将每个设置放在自己的函数中将是矫枉过正。

        我听说的另一条指导方针可能有助于您理解“一件事”概念:如果函数超过一两页,则将其内容分成多个子函数可能会更好。

        【讨论】:

          【解决方案7】:

          孤立地查看您的代码,很难说。您可能会争辩说您的函数做了两件事 - 更新设置然后保存更改。另外,您如何填充这些值,它们是作为参数传递给您的函数(首选)还是您的函数本身获取值(做其他事情)?

          我会关注Single Responsibility Principle,总结如下:

          改变班级的理由不应该不止一个

          并且同样可以应用于方法。在您的示例中,是否有理由更新设置但不保存它们?

          【讨论】:

            【解决方案8】:

            在我们的团队中,我们努力为每项职能准则遵循一个目的。为了帮助开发人员,我们在标准中添加了一个建议,即如果函数超过 25 行,他们会考虑重构。因此,如果您有 100 行代码设置属性,您可能会考虑按 SaveUserSettings、SaveNetworkSettings 等类别进行拆分。

            最终目标是使代码更具可读性。如果您采用您的方法并将其拆分为 20 个调用,每个调用设置一个属性,我认为跟踪和支持会更耗时。

            【讨论】:

              【解决方案9】:

              示例代码会更好地解决以下问题:何时使用属性以及何时在构造函数或方法上使用参数来设置对象状态。我知道.NET framework guidelines 中有一个关于此的部分,其中讨论了组件基本模式(许多属性和组件内部状态可能在第一次和最后一次分配之间无效)与其他模式(大量构造函数参数和方法参数和对象内部状态在每行代码执行后有效。

              【讨论】:

                【解决方案10】:

                如果你想拆分你的方法,我会考虑从对象的实际保存中断开值的映射。您可以说值的映射是一个单独的抽象级别。所以你会:

                public void save(){
                    mapSettings();
                    Settings.Default.Save();
                }
                
                private void mapSettings(){
                    Settings.Default.BaudRate = baudRate;
                    Settings.Default.COMPort = port;
                    Settings.Default.DataBits = dataBits;
                    Settings.Default.Handshake = handshake;
                    Settings.Default.Parity = parity;
                    Settings.Default.ReadTimeout = readTimeout;
                    Settings.Default.WriteTimeout = writeTimeout;
                    Settings.Default.CommunicationTimeout = communicationTimeout;
                }
                

                似乎映射可能会在其他地方重用,或者您可能想要重用。此外,如果数字设置增加,它们可以按类别进一步细分。

                在这种情况下,我不会争辩说它是否值得,我是否这样做取决于我的心情或天空中的云量。但是,是的,从技术上讲,您可以在这里拆分两个级别。

                【讨论】:

                  【解决方案11】:

                  如何知道一个函数是做一件事还是做多件事?它取决于抽象级别。 我尝试在两个示例中描述抽象级别(干净的代码书,第 3 章) 看这段代码

                  public function buildPage() {
                     $page = header();
                     $page .= body();
                     $page .= footer();
                     return $page;
                  }
                  

                  这个函数只做一件事,所有子函数都是 buildPage 短语的一部分

                  public function sendMail() {
                     $user = $this->getUser();
                     $this->mailer->content("send this message!")
                         ->to($user->email)->send();
                  }
                  

                  此函数需要用户电子邮件,因此在 getUser 函数的帮助下 sendMail 设法获取用户电子邮件。但是 $user = getUser() 没有在 sendMail 短语中描述 此功能的最佳实践是

                  public function sendMail($email,$message) {
                     $this->mailer->content($message)->to($email)->send();
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2011-01-20
                    • 1970-01-01
                    • 2019-09-27
                    • 2023-03-11
                    • 1970-01-01
                    • 2010-09-05
                    • 2019-12-13
                    • 2013-03-06
                    • 1970-01-01
                    相关资源
                    最近更新 更多