auto commit

This commit is contained in:
CyC2018 2018-06-07 21:51:31 +08:00
parent 4e0646dad6
commit 9164742ff0
2 changed files with 126 additions and 49 deletions

View File

@ -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 不包含尾部。
<div align="center"> <img src="../pics//05907ab4-42c5-4b5e-9388-6617f6c97bea.jpg"/> </div><br>
布尔相关的命名加上 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 来代替。

View File

@ -123,24 +123,22 @@
影片出租店应用程序,需要计算每位顾客的消费金额。
包括三个类Movie、Rental 和 CustomerRental 包含租赁的 Movie 以及天数
包括三个类Movie、Rental 和 Customer。
<div align="center"> <img src="../pics//c2f0c8e2-da66-498c-a38f-e1176abee29e.png"/> </div><br>
最开始的实现是把所有的计费代码都放在 Customer 类中。
可以发现,该代码没有使用 Customer 类中的任何信息,更多的是使用 Rental 类的信息,因此第一个可以重构的点就是把具体计费的代码移到 Rental 类中,然后 Customer 类的 getTotalCharge() 方法只需要调用 Rental 类中的计费方法即可。
最开始的实现是把所有的计费代码都放在 Customer 类中。可以发现,该代码没有使用 Customer 类中的任何信息,更多的是使用 Rental 类的信息,因此第一个可以重构的点就是把具体计费的代码移到 Rental 类中,然后 Customer 类的 getTotalCharge() 方法只需要调用 Rental 类中的计费方法即可。
```java
public class Customer {
class Customer {
private List<Rental> 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 {
<div align="center"> <img src="../pics//41026c79-dfc1-40f7-85ae-062910fd272b.png"/> </div><br>
但是我们需要允许一部影片可以在运行过程中改变其所属的分类,但是上述的继承方案却不可行,因为一个对象所属的类在编译过程就确定了。
有一条设计原则指示应该多用组合少用继承,这是因为组合比继承具有更高的灵活性。例如上面的继承方案,一部电影要改变它的计费方式,就要改变它所属的类,但是对象所属的类在编译时期就确定了,无法在运行过程中改变。(运行时多态可以在运行过程中改变一个父类引用指向的子类对象,但是无法改变一个对象所属的类。)
为了解决上述的问题,需要使用策略模式。引入 Price 类它有多种实现。Movie 组合了一个 Price 对象,并且在运行时可以改变组合的 Price 对象,从而使得它的计费方式发生改变。
策略模式就是使用组合替代继承的一种解决方案。引入 Price 类它有多种实现。Movie 组合了一个 Price 对象,并且在运行时可以改变组合的 Price 对象,从而使得它的计费方式发生改变。
<div align="center"> <img src="../pics//8c0b3ae1-1087-46f4-8637-8d46b4ae659c.png"/> </div><br>
@ -235,6 +231,107 @@ public class App {
<div align="center"> <img src="../pics//3ca58a41-8794-49c1-992e-de5d579a50d1.png"/> </div><br>
重构后的代码:
```java
class Customer {
private List<Rental> 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 可以做到。
测试应该能够完全自动化,并能检查测试的结果。
小步修改,频繁测试。