diff --git a/notes/代码可读性.md b/notes/代码可读性.md
index 4ba087cb..0be5c17d 100644
--- a/notes/代码可读性.md
+++ b/notes/代码可读性.md
@@ -3,7 +3,7 @@
* [二、用名字表达代码含义](#二用名字表达代码含义)
* [三、名字不能带来歧义](#三名字不能带来歧义)
* [四、良好的代码风格](#四良好的代码风格)
-* [五、编写注释](#五编写注释)
+* [五、为何编写注释](#五为何编写注释)
* [六、如何编写注释](#六如何编写注释)
* [七、提高控制流的可读性](#七提高控制流的可读性)
* [八、拆分长表达式](#八拆分长表达式)
@@ -43,12 +43,14 @@
起完名字要思考一下别人会对这个名字有何解读,会不会误解了原本想表达的含义。
-用 min、max 表示数量范围;用 first、last 表示访问空间的包含范围,begin、end 表示访问空间的排除范围,即 end 不包含尾部。
+布尔相关的命名加上 is、can、should、has 等前缀。
+
+- 用 min、max 表示数量范围;
+- 用 first、last 表示访问空间的包含范围;
+- begin、end 表示访问空间的排除范围,即 end 不包含尾部。
-布尔相关的命名加上 is、can、should、has 等前缀。
-
# 四、良好的代码风格
适当的空行和缩进。
@@ -61,11 +63,9 @@ int b = 11; // 注释
int c = 111; // 注释
```
-语句顺序不能随意,比如与 html 表单相关联的变量的赋值应该和表单在 html 中的顺序一致;
+语句顺序不能随意,比如与 html 表单相关联的变量的赋值应该和表单在 html 中的顺序一致。
-把相关的代码按块组织起来放在一起。
-
-# 五、编写注释
+# 五、为何编写注释
阅读代码首先会注意到注释,如果注释没太大作用,那么就会浪费代码阅读的时间。那些能直接看出含义的代码不需要写注释,特别是并不需要为每个方法都加上注释,比如那些简单的 getter 和 setter 方法,为这些方法写注释反而让代码可读性更差。
@@ -109,14 +109,6 @@ int add(int x, int y) {
}
```
-在很复杂的函数调用中对每个参数标上名字:
-
-```java
-int a = 1;
-int b = 2;
-int num = add(\* x = *\ a, \* y = *\ b);
-```
-
使用专业名词来缩短概念上的解释,比如用设计模式名来说明代码。
# 七、提高控制流的可读性
@@ -128,16 +120,6 @@ if (len < 10)
if (10 > len)
```
-if / else 条件语句,逻辑的处理顺序为:① 正逻辑;② 关键逻辑;③ 简单逻辑。
-
-```java
-if (a == b) {
- // 正逻辑
-} else{
- // 反逻辑
-}
-```
-
只有在逻辑简单的情况下使用 ? : 三目运算符来使代码更紧凑,否则应该拆分成 if / else;
do / while 的条件放在后面,不够简单明了,并且会有一些迷惑的地方,最好使用 while 来代替。
diff --git a/notes/重构.md b/notes/重构.md
index 947a5455..9a3242ba 100644
--- a/notes/重构.md
+++ b/notes/重构.md
@@ -123,24 +123,22 @@
影片出租店应用程序,需要计算每位顾客的消费金额。
-包括三个类:Movie、Rental 和 Customer,Rental 包含租赁的 Movie 以及天数。
+包括三个类:Movie、Rental 和 Customer。
-最开始的实现是把所有的计费代码都放在 Customer 类中。
-
-可以发现,该代码没有使用 Customer 类中的任何信息,更多的是使用 Rental 类的信息,因此第一个可以重构的点就是把具体计费的代码移到 Rental 类中,然后 Customer 类的 getTotalCharge() 方法只需要调用 Rental 类中的计费方法即可。
+最开始的实现是把所有的计费代码都放在 Customer 类中。可以发现,该代码没有使用 Customer 类中的任何信息,更多的是使用 Rental 类的信息,因此第一个可以重构的点就是把具体计费的代码移到 Rental 类中,然后 Customer 类的 getTotalCharge() 方法只需要调用 Rental 类中的计费方法即可。
```java
-public class Customer {
+class Customer {
private List rentals = new ArrayList<>();
- public void addRental(Rental rental) {
+ void addRental(Rental rental) {
rentals.add(rental);
}
- public double getTotalCharge() {
+ double getTotalCharge() {
double totalCharge = 0.0;
for (Rental rental : rentals) {
switch (rental.getMovie().getMovieType()) {
@@ -151,7 +149,6 @@ public class Customer {
totalCharge += rental.getDaysRented() * 2;
break;
case Movie.Type3:
- totalCharge += 1.5;
totalCharge += rental.getDaysRented() * 3;
break;
}
@@ -159,42 +156,41 @@ public class Customer {
return totalCharge;
}
}
-
```
```java
-public class Rental {
+class Rental {
private int daysRented;
private Movie movie;
- public Rental(int daysRented, Movie movie) {
+ Rental(int daysRented, Movie movie) {
this.daysRented = daysRented;
this.movie = movie;
}
- public Movie getMovie() {
+ Movie getMovie() {
return movie;
}
- public int getDaysRented() {
+ int getDaysRented() {
return daysRented;
}
}
```
```java
-public class Movie {
+class Movie {
- public static final int Type1 = 0, Type2 = 1, Type3 = 2;
+ static final int Type1 = 0, Type2 = 1, Type3 = 2;
private int type;
- public Movie(int type) {
+ Movie(int type) {
this.type = type;
}
- public int getMovieType() {
+ int getMovieType() {
return type;
}
}
@@ -223,9 +219,9 @@ public class App {
-但是我们需要允许一部影片可以在运行过程中改变其所属的分类,但是上述的继承方案却不可行,因为一个对象所属的类在编译过程就确定了。
+有一条设计原则指示应该多用组合少用继承,这是因为组合比继承具有更高的灵活性。例如上面的继承方案,一部电影要改变它的计费方式,就要改变它所属的类,但是对象所属的类在编译时期就确定了,无法在运行过程中改变。(运行时多态可以在运行过程中改变一个父类引用指向的子类对象,但是无法改变一个对象所属的类。)
-为了解决上述的问题,需要使用策略模式。引入 Price 类,它有多种实现。Movie 组合了一个 Price 对象,并且在运行时可以改变组合的 Price 对象,从而使得它的计费方式发生改变。
+策略模式就是使用组合替代继承的一种解决方案。引入 Price 类,它有多种实现。Movie 组合了一个 Price 对象,并且在运行时可以改变组合的 Price 对象,从而使得它的计费方式发生改变。
@@ -235,6 +231,107 @@ public class App {
+重构后的代码:
+
+```java
+class Customer {
+ private List rentals = new ArrayList<>();
+
+ void addRental(Rental rental) {
+ rentals.add(rental);
+ }
+
+ double getTotalCharge() {
+ double totalCharge = 0.0;
+ for (Rental rental : rentals) {
+ totalCharge += rental.getCharge();
+ }
+ return totalCharge;
+ }
+}
+```
+
+```java
+class Rental {
+ private int daysRented;
+
+ private Movie movie;
+
+ Rental(int daysRented, Movie movie) {
+ this.daysRented = daysRented;
+ this.movie = movie;
+ }
+
+ double getCharge() {
+ return daysRented * movie.getCharge();
+ }
+}
+```
+
+```java
+interface Price {
+ double getCharge();
+}
+```
+
+```java
+class Price1 implements Price {
+ @Override
+ public double getCharge() {
+ return 1;
+ }
+}
+```
+
+```java
+class Price2 implements Price {
+ @Override
+ public double getCharge() {
+ return 2;
+ }
+}
+```
+
+```java
+package imp2;
+
+class Price3 implements Price {
+ @Override
+ public double getCharge() {
+ return 3;
+ }
+}
+```
+
+```java
+class Movie {
+
+ private Price price;
+
+ Movie(Price price) {
+ this.price = price;
+ }
+
+ double getCharge() {
+ return price.getCharge();
+ }
+}
+```
+
+```java
+class App {
+
+ public static void main(String[] args) {
+ Customer customer = new Customer();
+ Rental rental1 = new Rental(1, new Movie(new Price1()));
+ Rental rental2 = new Rental(2, new Movie(new Price2()));
+ customer.addRental(rental1);
+ customer.addRental(rental2);
+ System.out.println(customer.getTotalCharge());
+ }
+}
+```
+
# 二、重构原则
## 定义
@@ -265,9 +362,7 @@ public class App {
## 修改接口
-如果重构手法改变了已发布的接口,就必须维护新旧两个接口。
-
-可以保留旧接口,让旧接口去调用新接口,并且使用 Java 提供的 @deprecation 将旧接口标记为弃用。
+如果重构手法改变了已发布的接口,就必须维护新旧两个接口。可以保留旧接口,让旧接口去调用新接口,并且使用 Java 提供的 @deprecation 将旧接口标记为弃用。
可见修改接口特别麻烦,因此除非真有必要,否则不要发布接口,并且不要过早发布接口。
@@ -467,7 +562,7 @@ Extract Method 会把很多参数和临时变量都当做参数,可以用 Repl
Java 可以使用 Junit 进行单元测试。
-测试应该能够完全自动化,并能检查测试的结果。Junit 可以做到。
+测试应该能够完全自动化,并能检查测试的结果。
小步修改,频繁测试。