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

本文介绍了一个租赁系统的重构过程,展示了如何通过逐步改进代码结构来提高软件的可维护性和可读性。具体步骤包括:建立测试环境、提取方法、移动方法、参数化方法等。最终实现了运用多态替换复杂的条件逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

重构之前

这里写图片描述

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());


    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值