zoukankan      html  css  js  c++  java
  • 重构-改善既有代码的设计 读书笔记一

    影片出租店的程序:计算每位顾客的消费金额并打印详单。
    操作者告诉程序:顾客租了哪些影片,租期多长。程序根据租赁时间和影片类型计算费用。
    影片分为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() + "
    ";
    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 += "	" + rental.getMovie().getTitle() + "	" + String.valueOf(rental.getCharge()) + "
    ";
    45         }
    46         result += "Amount owed is " + String.valueOf(getTotalAmount()) + "
    ";
    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
  • 相关阅读:
    Dynamics CRM for Outlook问题集
    Dynamics CRM
    VMWare安装CentOS-6.3-x86_64-minimal和LAMP
    Microsoft Dynamics CRM Update Rollup
    Reporting Service 迁移: 从2005到2008
    [转]非常好的vsftpd安装于配置
    关闭水滴直播平台 周鸿祎曾态度强硬
    贾跃亭此前曾公开表示,“法拉第未来计划于2
    爆出的法拉第未来(Faraday Future,以下简称“FF”)
    YII2笔记之三
  • 原文地址:https://www.cnblogs.com/mozq/p/10804886.html
Copyright © 2011-2022 走看看