代码气味是一大堆代码或一般编码模式,看起来可能表明代码库的整体结构和设计中存在更深层次的问题。
想一想代码气味是任何暗示应重构代码段的符号。并不是说代码有错误或无法正常工作-通常,有臭味的代码运行得很好-但有臭味的代码通常难以维护和扩展,这可能会导致技术问题(尤其是在大型项目中)。
1。紧密耦合
问题
紧密耦合是指两个对象非常依赖彼此的数据和/或功能,以至于修改一个对象需要修改另一个对象。当两个对象过于紧密地耦合在一起时,对代码进行更改可能是一场噩梦,并且每次更改都可能引入错误。
例如:
class Worker { Bike bike = new Bike(); public void commute() { bike.drive(); }}
,工人和自行车紧密相连。如果有一天您想开车而不是骑自行车上班怎么办?您必须进入Worker类,然后将所有与Bike相关的代码替换为Car相关代码。麻烦而且容易出错。
解决方案
您可以通过添加抽象层来放松耦合。在这种情况下,工人阶级不仅要驾驶自行车,还希望驾驶汽车,也许还有卡车,甚至是踏板车。这些都是车辆,不是吗?因此,创建一个Vehicle界面,该界面可让您根据需要插入和替换不同的Vehicle类型:
class Worker { Vehicle vehicle; public void changeVehicle(Vehicle v) { vehicle = v; } public void commute() { vehicle.drive(); }}interface Vehicle { void drive();}class Bike implements Vehicle { public void drive() { }}class Car implements Vehicle { public void drive() { }}
2。上帝对象
问题
上帝对象是庞大的类/模块,其中包含过多的变量和函数。它“知道太多"和“做太多",这有两个问题,这是有问题的。首先,其他类/模块过于依赖此类/数据(紧密耦合)。其次,程序的整体结构变得混乱不堪,因为所有东西都塞在了同一位置。
解决方案
根据要解决的问题分离其数据和功能,然后将这些分组转换为对象。如果您有上帝的物体,最好由许多较小的物体组成。
例如,假设您有一个可怕的User类:
class User { public String username; public String password; public String address; public String zipcode; public int age; ... public String getUsername() { return username; } public void setUsername(String u) { username = u; }}
您可以将其转换组成以下内容:
class User { Credentials credentials; Profile profile; ...}class Credentials { public String username; public String password; ... public String getUsername() { return username; } public void setUsername(String u) { username = u; }}
下次需要修改登录过程时,您不必遍历庞大的User类,因为Credentials类更易于管理!
问题
长函数的确切含义是:一个函数过长。虽然对于一个函数“太长"的代码行数没有特定的数字,但是当您看到它时,便是其中之一。这是上帝对象问题的一个较紧密范围的版本,一个长函数承担了太多责任。
解决方案
长函数应分为许多子类,功能,其中每个子功能都旨在处理单个任务或问题。理想情况下,原始的long函数将变成子函数调用列表,从而使代码更整洁,更易于阅读。
4。参数过多
问题
需要太多参数的函数(或类构造函数)存在问题,原因有两个。首先,它使代码的可读性降低,并且使其更难测试。但是第二点,更重要的是,这可能表明该功能的目的太含糊,并试图处理过多的职责。
解决方案
“多"是主观的参数列表,建议您不要对具有3个以上参数的任何函数保持警惕。当然,有时只有一个具有5个或什至6个参数的函数是有意义的,但前提是确实有一个很好的理由。
在大多数情况下,没有一个函数并且代码会最好将该功能分解为两个或多个不同的功能。与“长功能"代码的味道不同,不能仅通过用子功能替换代码来解决这一问题-功能本身需要划分并分解为涵盖不同职责的单独功能。
5。命名不正确的标识符
问题
一个或两个字母的变量名称。非描述函数名称。过度修饰的班级名称。用类型标记变量名(例如,b_isCounted为布尔变量)。最糟糕的是,在单个代码库中混合使用不同的命名方案。所有这些都会导致难以阅读,难以理解和难以维护的代码。
解决方案
为变量取好名字,函数和类是一项很难学习的技能。如果您要加入现有项目,请对其进行梳理并查看如何命名现有标识符。如果有样式指南,请记住并遵守。对于新项目,请考虑编写自己的样式指南并坚持使用。
通常,变量名应该简短但具有描述性。函数名称通常应至少包含一个动词,并且应该立即明白函数仅从其名称起的作用,但要避免填入过多的单词。类名也是如此。
6。魔术数字
问题
您正在浏览一些(希望)别人写的代码,并且发现了一些硬编码的数字。可能它们是if语句的一部分,或者可能是某些似乎没有道理的奥秘计算的一部分。您需要修改该功能,但无法理解数字的含义。提示头抓挠。
解决方案
在编写代码时,应不惜一切代价避免使用这些所谓的“幻数"。硬编码数字在编写时就很有意义,但是它们很快就会失去所有意义,尤其是在其他人尝试维护您的代码时。
一种解决方案是留下注释以解释数字,但是更好的选择是将幻数转换为常数变量(用于计算)或枚举(用于条件语句和switch语句)。通过给魔术数字起一个名字,使代码一目了然,可读性更强,并且不容易出错。
7。深度嵌套
问题
以深度嵌套的代码结束的主要方法有两种:循环和条件语句。深度嵌套的代码并不总是很糟糕,但是可能会引起问题,因为它很难解析(尤其是在变量命名不正确的情况下),甚至很难修改。
解决方案
如果您发现自己编写了一个两倍,三倍甚至四倍的for循环,则您的代码可能试图超出其自身的范围来查找数据。而是提供一种通过对包含数据的对象或模块进行函数调用来请求数据的方法。
另一方面,深度嵌套的条件语句通常表明您正在尝试在单个函数或类中处理太多逻辑。实际上,深层嵌套和长函数往往是并行的。如果您的代码中包含大量switch语句或嵌套的if-then-else语句,则可能要改用State Machine或Strategy模式。
深层嵌套在经验不足的游戏程序员中尤其普遍!
8。未处理的异常
问题
异常功能强大,但易于滥用。错误地使用throw-catch语句的懒惰程序员可能使调试工作成倍增加,即使不是不可能。例如,忽略或掩埋捕获的异常。
解决方案
与其忽略或掩埋捕获的异常,至少要打印出异常的堆栈跟踪,以便调试器可以工作用。保证程序无声地失败是保证将来头痛的良方!另外,与一般异常相比,更喜欢捕获特定异常。在有关如何正确处理异常的文章中了解更多信息。
9。重复代码
问题
您在程序的多个不相关区域中执行相同的确切逻辑。后来,您意识到您需要修改该逻辑,但不记得实现它的所有位置。您最终只能在8个位置中的5个位置进行更改,从而导致错误和不一致的行为。
解决方案
重复的代码是将其转换为代码的主要候选对象功能。例如,假设您正在开发一个聊天应用程序,并编写以下代码:
String queryUsername = getSomeUsername();boolean isUserOnline = false;for (String username : onlineUsers) { if (username.equals(queryUsername)) { isUserOnline = true; }}if (isUserOnline) { ...}
在代码中的其他地方,您意识到您需要执行相同的“此用户是否在线?"检查。您可以将其拉出到函数中,而不用复制粘贴循环:
public boolean isUserOnline(String queryUsername) { for (String username : onlineUsers) { if (username.equals(queryUsername)) { return true; } } return false;}
现在在代码中的任何位置,都可以使用isUserOnline()检查。如果您需要修改此逻辑,则可以对其进行调整,并将其应用于所有被调用的地方。
10。缺少注释
问题
该代码在任何地方都没有注释。没有函数的文档块,类的用法概述,算法的解释等。人们可能会争辩说,编写良好的代码不需要注释,但事实是,即使是编写最佳的代码也需要更多的精力来
解决方案
易于维护的代码库的目标应该是编写得足够好而不需要< / em>注释,但仍然有它们。而且,在编写注释时,请针对解释为什么存在一段代码的注释,而不是解释为什么在做什么。评论有益于心灵和理智。
如何编写不会发臭的代码
看起来似乎很明显,大多数代码气味源于对良好编程原理和性能的误解或忽视。模式。例如,对DRY原则的坚定遵守消除了大多数代码重复,而对“单一责任"原则的精通使几乎不可能创建可怕的上帝对象。
我们还建议阅读我们的文章,了解如何编写更整洁的东西。代码,它着眼于编程的更实际方面。如果您看不懂自己的代码并一目了然,那么其他人还会怎么做?干净的代码是无味的代码。
在编程方面,您最困扰什么?在下面的评论中与我们分享!
标签: