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

@ -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 可以做到。
测试应该能够完全自动化,并能检查测试的结果。
小步修改,频繁测试。