diff --git a/notes/重构.md b/notes/重构.md index 4803d5b6..4e3fd6a9 100644 --- a/notes/重构.md +++ b/notes/重构.md @@ -109,37 +109,68 @@ 在重构前,需要先构建好可靠的测试环境,确保安全地重构。 -重构是以微小的步伐修改程序,如果犯下错误,很容易便可以发现它。 +重构需要以微小的步伐修改程序,如果重构过程发生错误,很容易就能发现错误。 **案例分析** -影片出租店应用程序,包括三个类:Movie、Rental 和 Customer,Rental 包含租赁的 Movie 以及天数。 +影片出租店应用程序,需要计算每位顾客的消费金额。 -

+包括三个类:Movie、Rental 和 Customer,Rental 包含租赁的 Movie 以及天数。 -最开始的实现是把所有的计费代码都放在 Customer 类中,在变化发生时,需要对这部分代码进行更改。本案例中可能发生的变化有:一种类别的计费方式发生改变;添加新的电影类别。考虑到计费代码可能存在于多处,一旦发生改变时,就需要对所有计费代码进行修改。 +

-

+最开始的实现是把所有的计费代码都放在 Customer 类中。 -以下是继承 Movie 的多态方案。但是由于一部 Movie 的类别会动态改变,因此这种方案不可行。 +可以发现,该代码没有使用 Customer 类中的任何信息,更多的是使用 Rental 类的信息,因此第一个可以重构的点就是把具体计费的代码移到 Rental 类中,然后 Customer 类的 getTotalCharge() 方法只需要调用 Rental 类中的计费方法即可。 -

-引入 Price 来反应类别信息,通过组合的方式在 Movie 中加入 Price 对象,这样每种类别的计费方式都封装在不同的 Price 子类中,并且 Movie 对象也可以动态改变类别。这种方式可以很好地适应上述提到的变化。 +```java +class Customer... +double getTotalCharge() { + while (rentals.hasMoreElements()) { + double thisAmount = 0; + Rental each = (Rental) rentals.nextElement(); + switch (each.getMovie().getPriceCode()) { + case Movie.REGULAR: + thisAmount += 2; + if (each.getDaysRented() > 2) + thisAmount += (each.getDaysRented() - 2) * 1.5; + break; + case Movie.NEW_RELEASE: + thisAmount += each.getDaysRented() * 3; + break; + case Movie.CHILDRENS: + thisAmount += 1.5; + if (each.getDaysRented() > 3) + thisAmount += (each.getDaysRented() - 3) * 1.5; + break; + } +} +``` -

+使用 switch 的准则是:只能在对象自己的数据上使用,而不能在另一个对象的数据基础上使用。解释如下:switch 使用的数据通常是一组相关的数据,例如上面的代码使用了 Movie 的多种类别数据。当这组类别的数据发生改变时,例如上面的代码中增加 Movie 的类别或者修改一种 Movie 类别的计费方法,就需要修改 switch 代码。如果允许违反了准则,就会有多个地方的 switch 使用了这部分的数据,那么需要打开所有的 switch 代码进行修改。 -重构后的时序图和类图: +以下是继承 Movie 的多态解决方案,这种方案可以解决上述的 switch 问题,因为每种电影类别的计费方式都被放到了对应 Movie 子类中,当变化发生时,只需要去修改对应子类中的代码即可。 -

+

-

+但是由于 Movie 可以在其生命周期内修改自己的类别,一个对象却不能在生命周期内修改自己所属的内,因此这种方案不可行。可以通过使用策略模式来解决这种问题(原书写的是使用状态模式,但是这里应该为策略模式,具体可以参考设计模式内容)。 + +下图中,Price 有多种实现,Movie 组合了一个 Price 对象,并且在运行时可以改变组合的 Price 对象,从而使得它的计费方式发生改变。 + +

+ +重构后整体的类图和时序图如下: + +

+ +

# 第二章 重构原则 重构是对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。 -重构的好处:改进软件设计;使软件更容易理解;帮助找到 bug;提高编程速度。 +重构的好处:改进软件设计;使软件更容易理解;帮助找到 Bug;提高编程速度。 三次法则:第一次做某件事时只管去做;第二次做类似事情时可以去做;第三次再做类似的事,就应该重构。 diff --git a/pics/25d6d3d4-4726-47b1-a9cb-3316d1ff5dd5.png b/pics/25d6d3d4-4726-47b1-a9cb-3316d1ff5dd5.png new file mode 100644 index 00000000..7550da6b Binary files /dev/null and b/pics/25d6d3d4-4726-47b1-a9cb-3316d1ff5dd5.png differ diff --git a/pics/2a842a14-e4ab-4f37-83fa-f82c206fe426.png b/pics/2a842a14-e4ab-4f37-83fa-f82c206fe426.png new file mode 100644 index 00000000..e75e0e12 Binary files /dev/null and b/pics/2a842a14-e4ab-4f37-83fa-f82c206fe426.png differ diff --git a/pics/4440ad24-625b-489a-96c1-e5ab1b06a30f.png b/pics/4440ad24-625b-489a-96c1-e5ab1b06a30f.png new file mode 100644 index 00000000..fb68a74b Binary files /dev/null and b/pics/4440ad24-625b-489a-96c1-e5ab1b06a30f.png differ diff --git a/pics/76b48b4c-8999-4967-893b-832602e73285.png b/pics/76b48b4c-8999-4967-893b-832602e73285.png new file mode 100644 index 00000000..ce851687 Binary files /dev/null and b/pics/76b48b4c-8999-4967-893b-832602e73285.png differ diff --git a/pics/8c139711-3500-4f71-8456-c1adaf429ad0.png b/pics/8c139711-3500-4f71-8456-c1adaf429ad0.png new file mode 100644 index 00000000..4bd01d9c Binary files /dev/null and b/pics/8c139711-3500-4f71-8456-c1adaf429ad0.png differ