【发布时间】:2020-02-14 03:30:32
【问题描述】:
我正在通过Refactoring: Improving the Design of Existing Code (1st edition) 这本书学习如何重构 Java 代码。作者进行了如下所示的重构,并解释了他为什么这样做,我不清楚。有人可以帮我理解解释吗?该代码用于电影租赁软件。
public class Movie {
//Lets call these constants "priceCode".
public static final int CHILDRENS = 2;
public static final int REGULAR = 0;
public static final int NEW_RELEASE = 1;
//...more code here...
}
class Rental {
private Movie _movie;
private int _daysRented;
//...more code here...
}
重构之前:
class Rental...
double getCharge() {
double result = 0;
switch (getMovie().getPriceCode()) {
case Movie.REGULAR:
result += 2;
if (getDaysRented() > 2)
result += (getDaysRented() - 2) * 1.5;
break;
case Movie.NEW_RELEASE:
result += getDaysRented() * 3;
break;
case Movie.CHILDRENS:
result += 1.5;
if (getDaysRented() > 3)
result += (getDaysRented() - 3) * 1.5;
break;
}
return result;
}
我们把上面的方法代码移到已经存在的Movie类中。
重构之后:
class Movie...
double getCharge(int daysRented) {
double result = 0;
switch (getPriceCode()) {
case Movie.REGULAR:
result += 2;
if (daysRented > 2)
result += (daysRented - 2) * 1.5;
break;
case Movie.NEW_RELEASE:
result += daysRented * 3;
break;
case Movie.CHILDRENS:
result += 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
break;
}
return result;
}
作者的解释:
根据另一个对象的属性进行切换是个坏主意。如果你必须使用 switch 语句,它应该在你自己的数据上,而不是在别人的数据上。
为此,为了工作,我必须输入租期的长度,这当然是租期的数据。该方法有效地使用了两条数据,即租借的长度和电影的类型。 为什么我更喜欢将租借时长传递给电影而不是电影类型传递给租借?这是因为提议的更改都是关于添加新类型。类型信息通常更不稳定。如果我改变电影类型,我希望涟漪效应最小,所以我更喜欢计算电影中的电荷。
我的问题:
为什么基于另一个对象的属性进行切换是个坏主意?
这些事情的真正含义是“类型信息通常倾向于不稳定”和“最小的涟漪效应(已实现)”?这些模糊的词(volatile 和ipple)并不能清楚地解释这种重构的优势。
PS - 请注意,这不是最终代码。本书后面有更多的重构。我知道这是一本过时的 1990 年代的书。尽管如此,这本书看起来有很多关于设计代码的想法和概念,这些想法和概念在今天仍然有用。但是,我不确定这本书在 2020 年会有多大帮助。而且,这本书的最新版本 Refactoring: Improving the Design of Existing Code (2nd edition) 使用了我不知道的 Javascript。
【问题讨论】:
-
这个解释就像一本关于重构的书的想法一样奇怪。此外,您正在阅读一本写于 1999 年的书,其中讲授了一堆过时的概念(在单击链接之前我想知道它是否是 Java5 之前的书……它是)。如果我是你,我会把这本书送到博物馆,然后读一些类似有效的 java 初学者的东西。这本书比eclipse 还要早
-
重构后的代码改善了这些类之间的松散耦合,并封装了 Movie 的实现。当 Movie 的新 priceCode 到达时,它只需要在 Movie 类中处理,而不是在所有具有 Movie 作为字段的类中。但是代码前后都没有保持标准。通常是将 priceCode 设为 MovieType 枚举,这可以将 priceCode、乘法因子甚至整个 getCharge(int) 保留在枚举中 - 这可以完全消除 switch 语句的需要
-
我认为在这个例子的上下文中“类型信息通常倾向于不稳定”意味着像电影类型这样的枚举更有可能根据业务需求而改变。因此,他更喜欢将其封装在电影类中。这样,当添加新电影类型时,他只需要更新电影类。否则,他应该跟踪其他类中对 Movie 类型的所有引用并更新它。没有绝对的方法可以说这是否是一个坏主意。他所说的“涟漪效应”可能是指一个类的变化需要修改其他几个类的情况。
-
IMO,“学习如何重构...”并不是最好的主意,最好了解设计原则、编码标准和常见的最佳实践。之后在处理一些代码时,如果某段代码需要重构,这几乎是自然而然的事情。
-
一件事引起注意的是声明带有“_”前缀的变量 (
Movie _movie),这可能从来都不是 Java 中的代码编写标准。令人欣慰的是,这本书可能涵盖了有用的主题,但与此问题类似,读者必须了解其背后的概念,并且可能在大多数情况下,书中讨论的某些代码至少可以使用 Java8 实现更简单的实现。
标签: java refactoring