重构-改善既有代码的设计 读书笔记一

影片出租店的程序:计算每位顾客的消费金额并打印详单。
操作者告诉程序:顾客租了哪些影片,租期多长。程序根据租赁时间和影片类型计算费用。
影片分为3类:普通片,儿童片,新片。除了计算费用还要为常客计算积分,积分根据组片种类是否为新片而不同。

Movie(movieKind, name)
Rent(影片名称,租赁时间)
RentTotal(Rent列表)

阶段1:从statement()到htmlStatement()
使用的重构方法:
1.extract method(抽取逻辑,可能在多处使用的相同逻辑,只需要保留一份逻辑代码,而在使用时对该逻辑进行调用。
而不是写重复的逻辑代码。)

确保逻辑代码唯一,而不是逻辑代码重复。
即确保逻辑实体唯一,而不是逻辑实体重复。
确保只有一个该逻辑的实体,而不是多个该逻辑的实体。因为如果某个逻辑产生多个实体,必须维护它们的一致性。
唯一的逻辑实体 + 逻辑实体的多次调用。
原因:逻辑代码重复,当需要修改该逻辑代码时,必须确保该逻辑代码的所有实体都是一致性。
这个一致性维护工作难度根据逻辑实体分散程度增加,逻辑实体的个数增加,出错的概率也不断提升。

2.move method(函数搬家,函数应该放在它使用的数据的对象内)
调整修改代码,让其使用新函数,旧函数如果是public则可以保留,如果其他类还引用了旧函数,不需要修改它们。
3.replace temp with query。(使用函数而不是临时变量)

阶段2:结合变化量,影片的类型,限制变化的影响范围。本例中将影片类型的变化影响限制到Movie类中。
如果getCharge()和getRentPoints()方法在Movie类中,我们只需要在Movie类中修改类型,getCharge() getRentPoints()方法。
如果getCharge()和getRentPoints()方法在Rental类中,当影片类型发生变化,我们需要在Movie类中需改类型,并在Rental类中修改这2个方法。
尽管修改的东西都是一样的,但是后者在2个类中修改,前者在1个类中修改。显然前者更好。
所以把Rental中的getCharge()方法和getRentPoints()方法搬到Movie类中
方式:将Rental中的getCharge()方法和getRentPoints()方法搬到Movie类中

阶段3:使用多态替换类型代码
1.replace type code with state/strategy
1.self encapsulate field
2.move method
3.replace conditional with polymorphism

重构的节奏:测试小修改,测试小修改。。。

重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。
重构是对软件的小修改,但重构之中还可以包含另一个重构。

重构的目的:在不改变软件可观察行为的前提下,调整内部结构,使其更容易被理解和修改。
性能优化:在不改变软件可观察行为的前提下,调整内部结构,提高性能,但往往代码会变得更难理解。

使用重构技术开发软件:
时间分配给2种截然不同的行为:添加新功能,以及重构。
添加新功能时不应修改代码,只管添加功能。
重构时不应添加新功能,只管调整结构。
经常变换帽子,但无论何时都应该清楚自己戴的是哪顶帽子。

重构把我带到更高的理解层次。

重构使程序拥有良好的设计,而良好的设计使快速开发的根本。
如果没有良好的设计,某段时间你可能进展迅速,但恶劣的设计很快就让你的速度慢下来。你会花时间在调试上面,修改的时间
越来越长,因为你必须花更多的时间取理解系统、寻找重复的代码,随着你给程序打上一个有一个补丁,新特性需要更多的代码来实现。
真是个恶性循环。

何时重构?
重构本来就不是一件应该特别拨出时间做的事情,随时随地都可以。
如果你想做某件事情,而重构可以帮你把它做得更好,就用重构。
如果你想理解代码,而重构可以帮助你理解,那就重构。
如果你想添加新功能,重构可以帮助你理解代码,并更容易的添加新功能。
 1 package shop;
 2 
 3 public class Movie {
 4     public static final int NEW_RELEASE = 0;
 5     public static final int REGULAR = 1;
 6     public static final int CHILDREN = 2;
 7 
 8 //    private int priceCode;
 9     private String title;
10     private Price price;
11 
12     public Movie() {
13     }
14 
15     public Movie(String title, int priceCode) {
16         setPriceCode(priceCode);
17         this.title = title;
18     }
19 
20     public int getPriceCode() {
21         return price.getPriceCode();
22     }
23 
24     public void setPriceCode(int priceCode) {
25         switch (priceCode){
26             case Movie.NEW_RELEASE:
27                 price = new NewPrice();
28                 break;
29             case Movie.REGULAR:
30                 price = new RegularPrice();
31                 break;
32             case Movie.CHILDREN:
33                 price = new ChildrenPrice();
34                 break;
35             default:
36                 throw new IllegalArgumentException("非法的影片类型:" + priceCode);
37         }
38     }
39 
40     public String getTitle() {
41         return title;
42     }
43 
44     public void setTitle(String title) {
45         this.title = title;
46     }
47 
48     public double getCharge(int daysRent){
49         return price.getCharge(daysRent);
50 //        double result = 0;
51 //        switch(getPriceCode()){
52 //            case Movie.REGULAR:
53 //                result += 2;
54 //                if(daysRent > 2){
55 //                    result += (daysRent - 2) * 1.5;
56 //                }
57 //                break;
58 //            case Movie.NEW_RELEASE:
59 //                result += daysRent * 3;
60 //                break;
61 //            case Movie.CHILDREN:
62 //                result += 1.5;
63 //                if(daysRent > 3){
64 //                    result += (daysRent - 3) * 1.5;
65 //                }
66 //                break;
67 //        }
68 //        return result;
69     }
70 
71     public int getRentPoints(int daysRent){
72         return price.getRentPoints(daysRent);
73 //        int rentPoints = 1;
74 //        if(getPriceCode() == Movie.NEW_RELEASE
75 //                && daysRent > 1){
76 //            rentPoints++;
77 //        }
78 //        return rentPoints;
79     }
80 }
Movie
 1 package shop;
 2 
 3 public class Rental {
 4     private Movie movie;
 5     private int daysRent;
 6 
 7     public Rental(){}
 8 
 9     public Rental(Movie movie, int daysRent){
10         this.movie = movie;
11         this.daysRent = daysRent;
12     }
13 
14     public Movie getMovie() {
15         return movie;
16     }
17 
18     public void setMovie(Movie movie) {
19         this.movie = movie;
20     }
21 
22     public int getDaysRent() {
23         return daysRent;
24     }
25 
26     public void setDaysRent(int daysRent) {
27         this.daysRent = daysRent;
28     }
29 
30     public int getRentPoints(){
31         return getMovie().getRentPoints(getDaysRent());
32 //        int rentPoints = 1;
33 //        if(getMovie().getPriceCode() == Movie.NEW_RELEASE
34 //                && getDaysRent() > 1){
35 //            rentPoints++;
36 //        }
37 //        return rentPoints;
38     }
39 
40     public double getCharge(){
41         return getMovie().getCharge(getDaysRent());
42 //        double result = 0;
43 //        switch(this.getMovie().getPriceCode()){
44 //            case Movie.REGULAR:
45 //                result += 2;
46 //                if(this.getDaysRent() > 2){
47 //                    result += (this.getDaysRent() - 2) * 1.5;
48 //                }
49 //                break;
50 //            case Movie.NEW_RELEASE:
51 //                result += this.getDaysRent() * 3;
52 //                break;
53 //            case Movie.CHILDREN:
54 //                result += 1.5;
55 //                if(this.getDaysRent() > 3){
56 //                    result += (this.getDaysRent() - 3) * 1.5;
57 //                }
58 //                break;
59 //        }
60 //        return result;
61     }
62 }
Rental
 1 package shop;
 2 
 3 import java.util.ArrayList;
 4 
 5 public class CustomerOrder01 {
 6     private String name;
 7     private ArrayList<Rental> rentals = new ArrayList<>();
 8 
 9     public CustomerOrder01(String name){
10         this.name = name;
11     }
12 
13     public void addRental(Rental rental){
14         rentals.add(rental);
15     }
16 
17     public String statement(){
18         String result ="Rental Record for " + getName() + "\n";
19         for (Rental rental : rentals) {
20 //            double thisAmount = 0;
21 //            switch(rental.getMovie().getPriceCode()){
22 //                case Movie.REGULAR:
23 //                    thisAmount += 2;
24 //                    if(rental.getDaysRent() > 2){
25 //                        thisAmount += (rental.getDaysRent() - 2) * 1.5;
26 //                    }
27 //                    break;
28 //                case Movie.NEW_RELEASE:
29 //                    thisAmount += rental.getDaysRent() * 3;
30 //                case Movie.CHILDREN:
31 //                    thisAmount += 1.5;
32 //                    if(rental.getDaysRent() > 3){
33 //                        thisAmount += (rental.getDaysRent() - 3) * 1.5;
34 //                    }
35 //                    break;
36 //            }
37 //            thisAmount = amountFor(rental);
38 //            thisAmount = rental.getCharge();
39 //            rentPoints++;
40 //            if(rental.getMovie().getPriceCode() == Movie.NEW_RELEASE
41 //                && rental.getDaysRent() > 1){
42 //                rentPoints++;
43 //            }
44             result += "\t" + rental.getMovie().getTitle() + "\t" + String.valueOf(rental.getCharge()) + "\n";
45         }
46         result += "Amount owed is " + String.valueOf(getTotalAmount()) + "\n";
47         result += "You earned " + String.valueOf(getTotalRentPoints()) + " frequent renter points";
48         return result;
49     }
50 
51     public double amountFor(Rental rental){
52 //        double result = 0;
53 //        switch(rental.getMovie().getPriceCode()){
54 //            case Movie.REGULAR:
55 //                result += 2;
56 //                if(rental.getDaysRent() > 2){
57 //                    result += (rental.getDaysRent() - 2) * 1.5;
58 //                }
59 //                break;
60 //            case Movie.NEW_RELEASE:
61 //                result += rental.getDaysRent() * 3;
62 //                break;
63 //            case Movie.CHILDREN:
64 //                result += 1.5;
65 //                if(rental.getDaysRent() > 3){
66 //                    result += (rental.getDaysRent() - 3) * 1.5;
67 //                }
68 //                break;
69 //        }
70 //        return result;
71         return rental.getCharge();
72     }
73 
74     public double getTotalAmount(){
75         double totalAmount = 0;
76         for (Rental rental : rentals) {
77             totalAmount += rental.getCharge();
78         }
79         return totalAmount;
80     }
81 
82     public int getTotalRentPoints(){
83         int totalRentPoints = 0;
84         for (Rental rental : rentals) {
85             totalRentPoints += rental.getRentPoints();
86         }
87         return totalRentPoints;
88     }
89     public String getName(){
90         return name;
91     }
92 }
CustomerOrder
 1 package shop;
 2 
 3 public class CustomerTest01 {
 4     public static void main(String[] args) {
 5         Movie movie1 = new Movie("阿凡达", Movie.NEW_RELEASE);
 6         Movie movie2 = new Movie("僵尸世界大战", Movie.REGULAR);
 7         Movie movie3 = new Movie("熔炉", Movie.CHILDREN);
 8         Movie movie4 = new Movie("星际穿越", Movie.REGULAR);
 9 
10         Rental rental1 = new Rental(movie1,3);
11         Rental rental2 = new Rental(movie2,5);
12         Rental rental3 = new Rental(movie3,5);
13 
14         CustomerOrder01 customerOrder = new CustomerOrder01("liubei");
15         customerOrder.addRental(rental1);
16         customerOrder.addRental(rental2);
17         customerOrder.addRental(rental3);
18 
19         System.out.println(customerOrder.statement());
20     }
21 }
CustomerTest
 1 package shop;
 2 
 3 public abstract class Price {
 4     public abstract int getPriceCode();
 5 
 6     public abstract double getCharge(int daysRent);
 7 
 8     public int getRentPoints(int daysRent){
 9         return 1;
10 //        int rentPoints = 1;
11 //        if(getPriceCode() == Movie.NEW_RELEASE
12 //                && daysRent > 1){
13 //            rentPoints++;
14 //        }
15 //        return rentPoints;
16     }
17 }
Price
 1 package shop;
 2 
 3 public class NewPrice extends Price{
 4     @Override
 5     public int getPriceCode() {
 6         return Movie.NEW_RELEASE;
 7     }
 8 
 9     @Override
10     public double getCharge(int daysRent) {
11         return daysRent * 3;
12     }
13 
14     @Override
15     public int getRentPoints(int daysRent) {
16         return daysRent > 1 ? 2 : 1;
17     }
18 }
NewPrice
 1 package shop;
 2 
 3 public class ChildrenPrice extends Price {
 4     @Override
 5     public int getPriceCode(){
 6         return Movie.CHILDREN;
 7     }
 8 
 9     @Override
10     public double getCharge(int daysRent) {
11         double result = 1.5;
12         if(daysRent > 3){
13             result += (daysRent - 3) * 1.5;
14         }
15         return result;
16     }
17 }
ChildrenPrice
 1 package shop;
 2 
 3 public class RegularPrice extends Price {
 4     @Override
 5     public int getPriceCode() {
 6         return Movie.REGULAR;
 7     }
 8 
 9     @Override
10     public double getCharge(int daysRent) {
11         double result = 2;
12         if(daysRent > 2){
13             result += (daysRent - 2) * 1.5;
14         }
15         return result;
16     }
17 }
RegularPrice

猜你喜欢

转载自www.cnblogs.com/mozq/p/10804886.html