《重构改善既有代码的设计》第一个重构案例

来源:互联网 发布:资生堂淘宝有旗舰店吗 编辑:程序博客网 时间:2024/05/16 05:53

重构之前

这里写图片描述

Movie(影片)

public class Movie {    //儿童片     public static final int CHILDRENS=0;     //普通片     public static final int REGULAR=1;     //新片     public static final int NEW_RELEASE=2;     private String title;    private int priceCode;     public Movie(String title, int priceCode) {        this.title = title;        this.priceCode = priceCode;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public void setPriceCode(int priceCode) {        this.priceCode = priceCode;    }}

Rental(租赁)

public class Rental {    private Movie movie;    private int dayRented;    public Rental(Movie movie, int dayRented) {        this.movie = movie;        this.dayRented = dayRented;    }    public Movie getMovie() {        return movie;    }    public int getDayRented() {        return dayRented;    }  }

Customer(顾客)

class Customer {    private String _name;    private Vector _rentals = new Vector();    public Customer(String name) {        _name = name;    }    public void addRental(Rental arg) {        _rentals.addElement(arg);    }    public String getName() {        return _name;    }    public String statement(){        double totalAmount = 0;        int frequentRenterPoints = 0;        Enumeration rentals = _rentals.elements();        String result = "Rental Record for " + getName() + "\n";        while (rentals.hasMoreElements()) {            double thisAmount = 0;            Rental each = (Rental) rentals.nextElement();            /**             * 租碟的价格是根据碟的类型进行计算的,             * 一般的碟:             * 2块钱起租赁,超过两天每天1块五             * 新碟:             * 每天三块             * 儿童碟:             * 不足四天都是1.5,超过四天(包括)每天1.5             */            //determine amounts for each line            switch (each.getMovie().getPriceCode()) {                 case Movie.REGULAR:                    thisAmount += 2;                    if (each.getDaysRented() > 2) {                        thisAmount += (each.getDaysRented() - 2) * 1.5;                    }                    break;                case Movie.NEW_RELEASE:                    thisAmount += each.getDaysRented() * 3;                    break;                case Movie.CHILDRENS:                    thisAmount += 1.5;                    if (each.getDaysRented() > 3){                        thisAmount += (each.getDaysRented() - 3) * 1.5;                        break;                    }            }            // add frequent renter points            frequentRenterPoints ++;            // add bonus for a two day new release rental            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) {                frequentRenterPoints ++;            }            // show figures fo this rental            result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmount) + "\n";            totalAmount += thisAmount;        }        //add footer lines        result += "Amount owed is " + String.valueOf(totalAmount) + "\n";        result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points";        return result;    }}

这里写图片描述

开始重构

建立可靠的测试环境
重构第一步:增加方法,获取单个影片租赁花了费用
重构第二步:修改变量名称
重构第三步:因为这个方法只使用Rental类,没有使用Customer类,所以把这个方法从Customer类移到Rental类
重构第四步:搬移后,去除参数,同时改变函数名称
重构第五步:测试,看看有没有错误
重构第六步:将thisAmount直接使用each.getCharge()代替
重构第七步:提炼“常客积分计算”,也是把这个方法写到Rental类
重构第八步:把“获取总积分”提炼出来,把这个方法写到Customer类
重构第九步:将租期长度作为参数传入getCharge方法
重构第十步:将影片相关的费用、积分方法Move到Movie类中,将Rental的属性daysRented作为参数。
重构第十一步:运用多态取代与价格相关的条件逻辑。
创建Price价格类,作为抽象类给多种影片类型继承,关联到Movie影片类中

Rental(租赁)

public class Rental {    private Movie movie;    private int dayRented;    public Rental(Movie movie, int dayRented) {        this.movie = movie;        this.dayRented = dayRented;    }    public Movie getMovie() {        return movie;    }    public void setMovie(Movie movie) {        this.movie = movie;    }    public int getDayRented() {        return dayRented;    }    public void setDayRented(int dayRented) {        this.dayRented = dayRented;    }    int getFrequentRenterPoints() {        return movie.getFrequentRenterPoints(getDayRented());    }}

Customer(顾客)

public class Customer {    private String name;    // 动态数组    Vector _rentals = new Vector();    public Customer(String name) {        super();        this.name = name;    }    public String getName() {        return name;    }    public void addRentals(Rental arg) {        _rentals.addElement(arg);    }    public String statement() {        double totalAmount = 0;        int frequentRenterPoints = 0;        // Enumeration接口定义了从一个数据结构得到连续数据的手段        Enumeration rentals = _rentals.elements();        String result = "Rental Record for" + getName() + "\n";        while (rentals.hasMoreElements()) {            Rental each = (Rental) rentals.nextElement();            result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(each.getMovie().getPrice().getCharge(each.getDayRented())) + "\n";        }        result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";        result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + "frequent renter points";        return result;    }    private int getTotalFrequentRenterPoints(){        int result=0;        Enumeration rentals=_rentals.elements();        while(rentals.hasMoreElements()){            Rental each=(Rental)rentals.nextElement();            result+=each.getMovie().getFrequentRenterPoints(each.getDayRented());        }        return result;    }    private double getTotalCharge(){        double result =0;        Enumeration rentals=_rentals.elements();        while(rentals.hasMoreElements()){            Rental each=(Rental)rentals.nextElement();            result+=each.getMovie().getPrice().getCharge(each.getDayRented());        }        return result;    }}

Movie(影片)

public class Movie {    // 儿童片    public static final int CHILDRENS = 0;    // 普通片    public static final int REGULAR = 1;    // 新片    public static final int NEW_RELEASE = 2;    private String title;    private int priceCode;    public Movie(String title, int priceCode) {        this.title = title;        setPriceCode(priceCode);    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public int getPriceCode() {        return priceCode;    }    int getFrequentRenterPoints(int daysRented) {        if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)            return 2;        else            return 1;    }    private Price price;    public void setPriceCode(int arg) {        switch (arg) {        case REGULAR:            price = new RegularPrice();            break;        case CHILDRENS:            price = new ChildrenPrice();            break;        case NEW_RELEASE:            price = new NewReleasePrice();            break;        default:            throw new IllegalArgumentException("Incorrect Price Code");        }    }    public Price getPrice() {        return price;    }    public void setPrice(Price price) {        this.price = price;    }}

Price类

运用多态取代与价格相关的条件逻辑。
创建Price价格类,作为抽象类给多种影片类型继承,关联到Movie影片类中,
这里写图片描述
Price类:

abstract class Price {    abstract int getPriceCode();    abstract double getCharge(int daysRenter);}class ChildrenPrice extends Price {    int getPriceCode() {        return Movie.CHILDRENS;    }    double getCharge(int daysRented) {        double result = +1.5;        if (daysRented > 3) {            result += (daysRented - 3) * 1.5;        }        return result;    }}class NewReleasePrice extends Price {    int getPriceCode() {        return Movie.NEW_RELEASE;    }    double getCharge(int daysRented) {        return daysRented * 3;    }}class RegularPrice extends Price {    int getPriceCode() {        return Movie.REGULAR;    }    double getCharge(int daysRented) {        double result = 2;        if (daysRented > 2) {            result += (daysRented - 2) * 1.5;        }        return result;    }}

这里写图片描述
这里写图片描述

测试

public class Test{    public static void main(String[] args) {        Movie mov1 = new Movie("metal",2);        mov1.setPriceCode(2);        Rental ren = new Rental(mov1,8);        Movie mov2 = new Movie("apple",1);        mov2.setPriceCode(1);        Rental xxx = new Rental(mov2,6);        Customer cus = new Customer("Lee");        cus.addRental(ren);        cus.addRental(xxx);        System.out.println(cus.statement());    }}
原创粉丝点击