图像识别
作为软件开发人员,我们不仅要编写有效的代码,而且还要编写可维护的代码,这是我们的责任。 Martin Fowler在他的《重构:改进现有代码的设计》中将代码气味定义为:
通常对应于系统中更深层问题的表面指示
重构是在不影响代码外部行为的情况下改进代码内部结构的过程。 理想情况下,我们应该在添加新功能的同时重构旧代码。 与尝试一次完成所有操作相比,这将节省我们一些时间。
福勒的书是极好的资源,可以帮助我们识别并消除一些常见的代码异味。 在编写代码以满足新要求时,我们还应该避免这些代码的味道。
在本教程中,我们将探索其中的一些。
1.评论:
理想情况下,我们应该编写能说明一切的代码。 进行大量评论被认为是不好的做法。 当我们使用大量评论时,它们通常会随着时间的推移而失去同步。 对于有时设计不当的系统,它们有时还会起到除臭剂的作用。
如果我们有一个好的设计并且正确地命名了我们的类,方法和变量,那么代码将很容易将其目的传达给另一个开发人员。
一些开发人员喜欢在他们创建的新类上签名自己的名字。 我个人不建议这样做,因为使用任何版本控制系统都可以轻松地跟踪作者。
注释在某些情况下可能会很有用,但请谨慎使用。
2.重复的代码:
重复的代码是当我们在代码库的多个位置分布相似的代码时看到的代码味道。 这是一个结构不良的代码,我们应该找到某种方法以单独的方法提取出通用功能。
代码重复的问题在于,如果要进行更改,则必须修改所有这些文件以适应该更改。 我们有可能错过一些代码块中的更新。
让我们尽一切可能坚持DRY(不要重复自己)的原则。 根据DRY原则,我们不应该重写已经编写的功能。
3.长方法:
我们应该避免使用长方法,这是一种不好的代码味道。 太长的方法很难阅读,很难适应它的新变化。 在开发人员中经常争论多长时间。 就我个人而言,我更喜欢遵循方法大小的规则,该规则的大小不应超过十五行代码。 在大多数情况下,此规则对我来说非常有效。
每当我看到自己违反此规则时,就会问自己: “此方法仅做一件事情(SRP原理)吗?” 。 如果没有,那么我尝试在逻辑上将我的方法拆分为更有意义的方法。
尽管使用长方法有时会很好,但约束是我们应该有足够的理由来证明它合理。
4.大班:
不出所料,我们列表中的下一个是大型类代码气味。 大型课程通常也称为“上帝课程”或“斑点或黑洞课程”。
在大型系统中,我们经常会遇到这种代码异味。 随着系统的发展,某些类最终会在一段时间内支持添加到其中的许多功能。 尽早捕获此代码气味是个好主意。 如果一个类太大,那么以后将花费大量时间和精力进行修复。
根据单一职责原则(SRP),一个类必须恰好做一件事并且做到这一点。 在向现有类添加一些代码时,让我们利用开发人员的直觉并自问: “此类是否真的应该支持此功能?”。 如果没有,最好将其放置在其他位置。
5.长参数列表:
另一个类似的代码味道是长参数列表。 长参数列表的方法可能难以使用,并且由于疏忽而增加了错误映射的可能性:
public void doSomething(String name, int id, String deptCode, String regNumber) {
...
}
此处的解决方案是引入捕获上下文的参数对象。 因此,我们可以将上述方法改进为:
public void doSomething(Student student) {
...
}
在这里,我们已经实现了正确的封装。
6.数据类别:
数据类是仅包含数据成员及其获取器和设置器的类:
public class Student {
private int id;
private String name;
//constructor, getters and setters
}
这通常表明它可能不是一个很好的抽象。
尽管我们创建参数对象来解决“长参数”代码的气味,但理想情况下,我们应该设计类,而不仅仅是存储数据。
我们应该问类似的问题: “我可以向当前在其他地方处理的此类添加一些功能吗?”
有时,当我们在代码库中的多个位置处理了这些数据类的功能时,就会意识到会出现重复的代码异味。
7.发散类:
当我们意识到由于许多不同的原因而不得不以多种不同的方式更改类时,会产生不同的类代码气味。
正如我们前面讨论的,类应仅具有一个特定的目的。 如果是这样,我们就没有什么理由对类进行更改,并且也没有太多理由要在其中进行更改。
如果我们发现自己以多种方式更改了一个类,那么这很好地表明该类的职责需要分解为单独的类。
8.消息链:
消息链是一种代码味道,我们在对象上调用一个方法,然后在该返回的对象上调用另一个方法,依此类推:
int id = obj.getDept().getSubDept().getHOD().getId();
较长的消息链使我们的系统变得僵硬,难以独立测试。
它通常还违反Demeter法则,该法则规定了良好的面向对象设计应允许调用哪些方法。
9. Shot弹枪手术:
realize弹枪手术是一种代码气味,当我们意识到我们必须触摸许多类以针对一个简单的要求进行更改时,就会发生这种气味。 当触及我们代码库中的许多地方时,很可能会引入错误并破坏现有的实现。
对于设计良好的系统,理想的情况是,小的更改将需要在本地更改到一两个位置。 虽然,这很难实现,而且无论我们对代码的设计水平如何,有时都需要进行shot弹枪手术。
我们可以通过移动方法来解决the弹枪手术代码的气味。 如果更改要求我们修改多个类中的方法,我们应该问自己: “这些方法应该合并为一两个类吗?” 然后让我们的开发者本能引导我们。
10.功能嫉妒:
功能嫉妒是一种代码气味,当我们拥有的方法对其他类的详细信息比对它所在的类更感兴趣时,就会发生这种情况。
如果两个或多个方法总是相互交谈,则它们很可能必须属于同一类。
11.不适当的亲密关系:
当两个类通过双向通信彼此之间过于依赖时,这是不适当的亲密代码气味。
在班级之间进行双向交流使他们紧密地联系在一起。 我们至少应该将某些方法排除在一个单独的类之外,以期消除循环。 我们应该设计易于理解和维护的类。
12.原始痴迷:
顾名思义,有时我们过于依赖原始类型。 尽管我们在代码中需要基元,但它们应存在于代码的最低级别。
我们应该避免过度使用原语,并在需要时定义合适的类。
13.投机性:
有时,我们会过度设计诸如定义超类或某些当前不需要的代码之类的东西,但总有一天会觉得有用。 此代码气味被称为推测性普遍性。
敏捷开发促进采用及时设计。 我们的设计应该保持简单,并且应该足以支持当前的功能。 用户需求经常快速变化,因此,仅在必要时才应引入概括。 否则,我们可能最终将时间浪费在最终从未使用的设计上。
14.拒绝的请求:
当子类继承某些东西但不需要它时,将出现拒绝的请求代码气味。
如果子类继承了它们不使用的东西,则它们可能不是超类的合适子类:
public class Bird {
void fly() {
System.out.println( "Flying!!" );
}
}
public class Ostrich extends Bird {
void fly() {
throw new IllegalStateException( "An ostrich can't fly" );
}
}
显然,鸵鸟不会飞行,因此这是拒绝请求代码气味的一个示例。 我们可以通过以下方式之一来处理此代码异味:
- 要么不要在超类中定义不需要的行为,要么
- 将它们创建为单独的独立类
结论:
在本教程中,我们研究了一些代码气味,并学习了如何避免和处理它们。
该列表显然并不详尽,但可以证明是快速入门指南。
翻译自: https://www.javacodegeeks.com/2019/09/identifying-code-smells-in-java.html
图像识别