当前位置: 首页 > 科技观察

用例子告诉你如何重构有异味的代码

时间:2023-03-22 16:16:52 科技观察

如果有异味的代码,说明你的代码写的不够好,需要重构让它们成为干净的代码。在本文中,我将通过GitHub上的真实项目解释代码异味,并向您展示如何重构它们。重复代码和重复逻辑开发人员通常很懒惰,在某种程度上,这并不是一件坏事。但是,因为懒惰而走上复制粘贴代码的道路是错误的。这会导致最常见的代码异味、逻辑重复,如下所示。为了摆脱这种代码味道,我们需要将红色部分提取到一个单独的方法中,以便它们可以在其他地方重用。长方法和臃肿的类我们都犯了这样的错误,即在现有方法中添加if()或for()语句来验证用户输入或检查用户是否已登录。我们真的不应该这样做。如果您必须进行这些验证,您应该创建自己的方法。该方法的长度应在4到20行之间,如果超过20行,则可以将其中的一些提取到另一个方法中。同样的规则也适用于类,根据单一职责原则,方法或类越小越好。相同或不同类中的重复方法另一种代码味道是多个方法提供相同的功能,如下图所示。发散变化如果你了解SOLID原则,尤其是单一职责原则,那么你应该知道修改一个类应该有一个单一的原因。也就是说,User类不应具有与产品或文件转换相关的功能。您可以通过将不相关的方法提取到Product类或FileSystem类来清除这种代码味道。ShotgunSurgery这与发散变化完全相反。这种代码味道会让你因为一个需求修改多个类。例如,你想创建一个新的用户规则(比如“Supper-Admin”),然后你发现为了添加这个规则,你需要修改Profile、Products和Employees类中的一些方法。在这种情况下,请考虑将这些方法放在一个单独的类中。FeatureEnvy有时您会发现一个类中的方法大量使用了另一个类。在这种情况下,您可能会考虑将该方法移动到它使用的类中。如下所示。将getFullAddress()从User类移动到ContactInfo类不是更好吗?因为它调用了ContactInfo类的很多方法。数据块有时,您会发现许多函数具有相同的参数列表,这会导致数据块的不良代码味道。查看下面的示例,您会发现几乎所有类型的预订都需要提供护照信息。在这种情况下,最好将护照信息移动到PassportInfo类中,然后将PassportInfo对象传递给预订方法。这是重用代码的一个很好的例子。请记住,长参数列表更容易出现错误和代码冲突,并且难以进行单元测试。对原始数据的痴迷当您在应用程序中到处使用原始数据类型时,就会出现这种代码味道。例如,电话号码使用整数,货币符号使用字符串。如果你正在这样做,请先看看下面的课程。代码中的地址被定义为数组,这会导致两个问题,例如,每次我们需要使用它时都将地址硬编码。那么,为什么不创建一个Address类呢?现在,每次我们需要添加或编辑地址时,我们只需要修改地址类。另外,如果我们需要添加一个新的“联系我们”方法,我们添加一个新的ContactUs类。这样,每个类都有自己的单一职责。switch语句您可能想知道为什么使用switch语句实际上是一件坏事。虽然使用switch语句不一定总是不好的,但在下面的示例中,您可以看到switch语句的代码块不仅很大而且不可提取。当代码块变大时,您将无法将其拆分为更小的方法。如果你的switch语句块不是很大,那么你可以继续使用它们。例如,工厂模式使用switch语句。并行继承有时我想知道并行继承是不是一种不好的做法。在讨论它是否是一种糟糕的代码味道之前,让我们先解释一下并行继承的概念。从上图中可以看出,每当我们创建一个新的部门类时,我们还需要创建一个权限类,这将导致前面提到的shotgunchangecodesmell。惰性类惰性类是做的很少的类。还记得下面这些代码吗?我们将地址移到了一个单独的类中,但我们没有为热线做同样的事情,因为它可能只有3行代码。因此,一旦找到这些惰性类,就应该将它们移除。临时字段当类实例的某些变量只是偶尔使用时,临时字段是一种代码味道。查看下面的示例,您会注意到$name和$contactDetails仅在notify()方法中使用。那么为什么不将它们作为方法参数传递。消息链当一个类使用另一个类时,消息链代码会产生异味,而另一个类又使用另一个类,依此类推。在下图中,您可以看到Employee->EmployeeConfig->Config。您可以通过缩短链条(到Employee->Config)使代码更清晰。不适当的亲和力有时一个类的方法需要知道太多关于另一个类的内部状态或数据的信息。如下图所示,notify()方法位于User类中,但它使用了UserContactDetails类的许多内部方法。在这种情况下,最好将此逻辑从User类移至UserContactDetails类并添加一个getWelcomeMessage($userName)方法。有时,您会发现一个类的许多方法除了将调用委托给另一个类外什么都不做。在这种情况下,这个类被认为是一个中间人,大部分时间都可以避免使用它。注意:在Facade设计模式中,中间人在某些情况下会很有帮助。具有不同接口但相同目的的类通常,由于团队之间缺乏沟通,会创建两个不同的类来实现相同的目的,这意味着代码重复。不完整的库第三方库并不总能为您提供应用程序所需的所有功能。在下面的示例中,处理文档的库可以按ID获取一个文档或一次获取所有文档。如果您需要获取特定用户的所有文档怎么办?在这种情况下,您需要在不直接修改原始类的情况下扩展Document类的功能。这时候就可以使用装饰模式了,如下图。现在,您可以使用DocumentsDecorator类代替Documents类。注释您可能会感到惊讶,但不正确地使用注释也是一种代码味道。以下是我的一些建议:删除不必要的评论。如果代码很容易理解,就不要添加额外的注释。不要留下遗留代码的评论。删除用于调试的注释,如var_dump、echo等。SpeculativeGenerality是一种与许多开发人员没有注意到的过早优化相关的代码味道。规划期间要考虑的一些注意事项:不要过度规划您的代码。不要试图涵盖未来只有1%的可能性发生的情况。可以牺牲一些速度来使算法更简单,尤其是当您不需要应用程序立即给出结果时。当应用程序运行缓慢时,即使只有100个用户,也需要对其进行优化。英文原文:https://codeburst.io/write-clean-code-and-get-rid-of-code-smells-aea271f30318【责任编辑:庞桂玉电话:(010)68476606】