本章通过1个案例,逐步的感受下重构

案例说明

这是一个非常简单的案例,展示了一个影片出租店用的程序,计算每一位顾客的消费金额并打印详单的模块,同时还需要计算每一位客人的积分。
抽象了三个实体:影片(片名、片类型)、租赁(影片、租赁天数)、顾客(姓名、租赁清单),

代码详见下面的三个类以及测试类。

customer.java

mport java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            double thisAmount = 0;
            Rental each = rentalEnumeration.nextElement();

            // determine amounts for each line
            switch (each.getMovie().getPriceCode()) {
                case Movie.REGULAR:
                    thisAmount += 2;
                    if (each.getDayRented() > 2) {
                        thisAmount += (each.getDayRented() - 2) * 1.5;
                    }
                    break;
                case Movie.NEW_RELEASE:
                    thisAmount += each.getDayRented() * 3;
                    break;
                case Movie.CHILDREN:
                    thisAmount += 1.5;
                    if (each.getDayRented() > 3) {
                        thisAmount += (each.getDayRented() - 3) * 1.5;
                    }
                    break;
            }

            // add frequent renter points
            frequentRenterPointers++;
            // add bonus for two day new release rental
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDayRented() > 1) {
                frequentRenterPointers++;
            }

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + thisAmount + "\n";
            totalAmount += thisAmount;
        }

        // add footer lines
        result += "Amount owed is " + totalAmount + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }
}

Movie.java

public class Movie {
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;
    public static final int CHILDREN = 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 int getPriceCode() {
        return priceCode;
    }

    public void setPriceCode(int priceCode) {
        this.priceCode = priceCode;
    }
}

 

 

public class Rental {
    private Movie movie;
    private int dayRented;

    public Movie getMovie() {
        return movie;
    }

    public int getDayRented() {
        return dayRented;
    }

    public Rental(Movie movie, int dayRented) {
        this.movie = movie;
        this.dayRented = dayRented;

    }
}

 

 

测试类:用于每次重构后,确认没有错误,影响原有的功能;

import org.junit.Assert;

public class TestOutput {

    @org.junit.Test
    public void Should_get_correct_statement() {
        // 三部影片
        Movie movie1 = new Movie("xxxxx", Movie.NEW_RELEASE);
        Movie movie2 = new Movie("AAAAA", Movie.CHILDREN);
        Movie movie3 = new Movie("DDDDD", Movie.REGULAR);

        //两名顾客
        Customer customer1 = new Customer("H1212");
        Customer customer2 = new Customer("J1212");

        //顾客租约
        Rental rental1 = new Rental(movie1, 10);
        Rental rental2 = new Rental(movie2, 1);
        Rental rental3 = new Rental(movie3, 3);
        customer1.addRental(rental1);
        customer1.addRental(rental2);
        customer2.addRental(rental2);
        customer2.addRental(rental3);

        Assert.assertEquals(customer1.statement(), "Rental Records for H1212\n" +
                "\txxxxx\t30.0\n" +
                "\tAAAAA\t1.5\n" +
                "Amount owed is 31.5\n" +
                "You earned 3 frequent renter points");
        Assert.assertEquals(customer2.statement(), "Rental Records for J1212\n" +
                "\tAAAAA\t1.5\n" +
                "\tDDDDD\t3.5\n" +
                "Amount owed is 5.0\n" +
                "You earned 2 frequent renter points");
    }
}

Customer提供了 statement 方法来输出租赁清单信息 ;

 

如果你发现自己需要为程序添加一个特性,而代码结构使你无法方便达成目的,那就重构那个程序,使特性的添加比较容易进行,然后再添加特性。
 

1 重构第一步,准备测试类

重构的第一步就是要为即将修改的代码建立一组可靠的测试环境,这些测试是必要的,避免因为重构带来新的 bug。

测试类已经在上面写好了。 

重构之前,首先检查自己是否有一套可靠的测试机制,这些测试必须有自我检验的能力。

其中我们发现statement 方法(Long Method),需要分解长函数,把较小的代码移至更合适的地方。重构 statement 可以分以下几个步骤: 

 

2 提炼 Switch 语句,提炼到单独的函数中比较合适。

注意两个临时变量,thisAmount 和 each,需要处理;
任何一个傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员。 

提炼amountFor函数:

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            double thisAmount = 0;
            Rental each = rentalEnumeration.nextElement();

            thisAmount = amountFor(each);

            // add frequent renter points
            frequentRenterPointers++;
            // add bonus for two day new release rental
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDayRented() > 1) {
                frequentRenterPointers++;
            }

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + thisAmount + "\n";
            totalAmount += thisAmount;
        }

        // add footer lines
        result += "Amount owed is " + totalAmount + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }

    private double amountFor(Rental each) {
        double thisAmount = 0;
        switch (each.getMovie().getPriceCode()) {
            case Movie.REGULAR:
                thisAmount += 2;
                if (each.getDayRented() > 2) {
                    thisAmount += (each.getDayRented() - 2) * 1.5;
                }
                break;
            case Movie.NEW_RELEASE:
                thisAmount += each.getDayRented() * 3;
                break;
            case Movie.CHILDREN:
                thisAmount += 1.5;
                if (each.getDayRented() > 3) {
                    thisAmount += (each.getDayRented() - 3) * 1.5;
                }
                break;
        }
        return thisAmount;
    }
}

 

3 修改变量名称:amountFor内的变量名称

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            double thisAmount = 0;
            Rental each = rentalEnumeration.nextElement();

            thisAmount = amountFor(each);

            // add frequent renter points
            frequentRenterPointers++;
            // add bonus for two day new release rental
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDayRented() > 1) {
                frequentRenterPointers++;
            }

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + thisAmount + "\n";
            totalAmount += thisAmount;
        }

        // add footer lines
        result += "Amount owed is " + totalAmount + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }


    private double amountFor(Rental aRental) {
        double result = 0;
        switch (aRental.getMovie().getPriceCode()) {
            case Movie.REGULAR:
                result += 2;
                if (aRental.getDayRented() > 2) {
                    result += (aRental.getDayRented() - 2) * 1.5;
                }
                break;
            case Movie.NEW_RELEASE:
                result += aRental.getDayRented() * 3;
                break;
            case Movie.CHILDREN:
                result += 1.5;
                if (aRental.getDayRented() > 3) {
                    result += (aRental.getDayRented() - 3) * 1.5;
                }
                break;
        }
        return result;
    }
}

 

 

4 搬移金额代码:amountFor使用的更多的是来自Rental类的信息,将其移动到rental类

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            double thisAmount = 0;
            Rental each = rentalEnumeration.nextElement();

            thisAmount = amountFor(each);

            // add frequent renter points
            frequentRenterPointers++;
            // add bonus for two day new release rental
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDayRented() > 1) {
                frequentRenterPointers++;
            }

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + thisAmount + "\n";
            totalAmount += thisAmount;
        }

        // add footer lines
        result += "Amount owed is " + totalAmount + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }

    private double amountFor(Rental aRental) {
        return aRental.getCharge();
    }
}


public class Rental {
    private Movie movie;
    private int dayRented;

    public Movie getMovie() {
        return movie;
    }

    public int getDayRented() {
        return dayRented;
    }

    public Rental(Movie movie, int dayRented) {
        this.movie = movie;
        this.dayRented = dayRented;
    }

    public double getCharge() {
        double result = 0;
        switch (getMovie().getPriceCode()) {
            case Movie.REGULAR:
                result += 2;
                if (getDayRented() > 2) {
                    result += (getDayRented() - 2) * 1.5;
                }
                break;
            case Movie.NEW_RELEASE:
                result += getDayRented() * 3;
                break;
            case Movie.CHILDREN:
                result += 1.5;
                if (getDayRented() > 3) {
                    result += (getDayRented() - 3) * 1.5;
                }
                break;
        }
        return result;
    }
}

 

 

5 寻找旧函数的所有引用点,删除无用的旧函数,其实就是内联函数:cmd+option+N

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            double thisAmount = 0;
            Rental each = rentalEnumeration.nextElement();

            thisAmount = each.getCharge();

            // add frequent renter points
            frequentRenterPointers++;
            // add bonus for two day new release rental
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDayRented() > 1) {
                frequentRenterPointers++;
            }

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + thisAmount + "\n";
            totalAmount += thisAmount;
        }

        // add footer lines
        result += "Amount owed is " + totalAmount + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }
}

 

 

6 继续内联,删除无用的临时变量

删除无用的临时变量, thisAmount 只是接受了一下 getCharge(),后面没有作任何变化,

可以采用以查询替换变量原则去除变量 thisAmount,暂时先不讨论两次计算带来的性能开销,这个完全可以优化掉。

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            Rental each = rentalEnumeration.nextElement();

            // add frequent renter points
            frequentRenterPointers++;
            // add bonus for two day new release rental
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDayRented() > 1) {
                frequentRenterPointers++;
            }

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + each.getCharge() + "\n";
            totalAmount += each.getCharge();
        }

        // add footer lines
        result += "Amount owed is " + totalAmount + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }
}

 

 

7 提炼”常客积分计算“代码,FrequentRenterPoint

提炼完成函数后,放入Rental类中;

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            Rental each = rentalEnumeration.nextElement();

            frequentRenterPointers += each.getFrequentRenterPoints();

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + each.getCharge() + "\n";
            totalAmount += each.getCharge();
        }

        // add footer lines
        result += "Amount owed is " + totalAmount + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }
}


public class Rental {
    private Movie movie;
    private int dayRented;

    public Movie getMovie() {
        return movie;
    }

    public int getDayRented() {
        return dayRented;
    }

    public Rental(Movie movie, int dayRented) {
        this.movie = movie;
        this.dayRented = dayRented;
    }

    public double getCharge() {
        double result = 0;
        switch (getMovie().getPriceCode()) {
            case Movie.REGULAR:
                result += 2;
                if (getDayRented() > 2) {
                    result += (getDayRented() - 2) * 1.5;
                }
                break;
            case Movie.NEW_RELEASE:
                result += getDayRented() * 3;
                break;
            case Movie.CHILDREN:
                result += 1.5;
                if (getDayRented() > 3) {
                    result += (getDayRented() - 3) * 1.5;
                }
                break;
        }
        return result;
    }

    int getFrequentRenterPoints() {
        if ((getMovie().getPriceCode() == Movie.NEW_RELEASE) && getDayRented() > 1) {
            return 2;
        }
        return 1;//不喜欢用else
    }
}

 

8 去除临时变量,使用查询代替

去除totalAmount和frequentRenterPointers 临时变量:
经过上述重构之后,发现临时变量依旧是一个灾难,就需要再使用用查询代替临时变量(Replace Temp With Query)的手法来清理这两个变量:
totalAmount:

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        int frequentRenterPointers = 0;
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            Rental each = rentalEnumeration.nextElement();

            frequentRenterPointers += each.getFrequentRenterPoints();

            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + each.getCharge() + "\n";
        }

        // add footer lines
        result += "Amount owed is " + getTotalCharge() + "\n";
        result += "You earned " + frequentRenterPointers + " frequent renter points";
        return result;
    }

    private double getTotalCharge() {
        double result = 0;
        Enumeration rentalList = rentals.elements();
        while (rentalList.hasMoreElements()) {
            Rental each = (Rental) rentalList.nextElement();
            result += each.getCharge();
        }
        return result;
    }
}

frequentRenterPointers:

import java.util.Enumeration;
import java.util.Vector;

public class Customer {

    private String name;
    private Vector<Rental> rentals = new Vector<>();

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addRental(Rental rental) {
        rentals.add(rental);
    }

    public String statement() {
        Enumeration<Rental> rentalEnumeration = rentals.elements();
        String result = "Rental Records for " + getName() + "\n";

        while (rentalEnumeration.hasMoreElements()) {
            Rental each = rentalEnumeration.nextElement();


            //show figures for this rental
            result += "\t" + each.getMovie().getTitle() + "\t" + each.getCharge() + "\n";
        }

        // add footer lines
        result += "Amount owed is " + getTotalCharge() + "\n";
        result += "You earned " + getFrequentRenterPointers() + " frequent renter points";
        return result;
    }

    private double getTotalCharge() {
        double result = 0;
        Enumeration rentalList = rentals.elements();
        while (rentalList.hasMoreElements()) {
            Rental each = (Rental) rentalList.nextElement();
            result += each.getCharge();
        }
        return result;
    }

    private int getFrequentRenterPointers() {
        int result = 0;
        Enumeration rentalList = rentals.elements();
        while (rentalList.hasMoreElements()) {
            Rental each = (Rental) rentalList.nextElement();
            result += each.getFrequentRenterPoints();
        }
        return result;

    }
}

 

 

9 switch语句的移动

switch应该放在正确位置:根据movie选择,所以放到movie中

最好不要在另一个对象的属性基础上运用Switch语句,如果不得不用,也应该咋对象自己的数据上使用,而不是别人的身上;

public class Movie {
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;
    public static final int CHILDREN = 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 int getPriceCode() {
        return priceCode;
    }

    public void setPriceCode(int priceCode) {
        this.priceCode = priceCode;
    }

    public double getCharge(int dayRented) {
        double result = 0;
        switch (getPriceCode()) {
            case Movie.REGULAR:
                result += 2;
                if (dayRented > 2) {
                    result += (dayRented - 2) * 1.5;
                }
                break;
            case Movie.NEW_RELEASE:
                result += dayRented * 3;
                break;
            case Movie.CHILDREN:
                result += 1.5;
                if (dayRented > 3) {
                    result += (dayRented - 3) * 1.5;
                }
                break;
        }
        return result;
    }

    public int getFrequentRenterPoints(int dayRented) {
        if ((getPriceCode() == Movie.NEW_RELEASE) && dayRented > 1) {
            return 2;
        }
        return 1;//不喜欢用else
    }
}

public class Rental {
    private Movie movie;
    private int dayRented;

    public Movie getMovie() {
        return movie;
    }

    public int getDayRented() {
        return dayRented;
    }

    public Rental(Movie movie, int dayRented) {
        this.movie = movie;
        this.dayRented = dayRented;
    }

    public double getCharge() {
        return movie.getCharge(dayRented);
    }

    int getFrequentRenterPoints() {
        return movie.getFrequentRenterPoints(dayRented);
    }
}

 

 

10 继承体系

创建price,分别不用类型继承;

public class Movie {
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;
    public static final int CHILDREN = 2;

    private String title;
    private int priceCode;
    private Price price;

    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 price.getPriceCode();
    }

    public void setPriceCode(int priceCode) {
        switch (priceCode) {
            case REGULAR:
                price = new RegularPrice();
                break;
            case CHILDREN:
                price = new ChildrensPrice();
                break;
            case NEW_RELEASE:
                price = new NewReleasePrice();
                break;
            default:
                throw new IllegalArgumentException("Incorrect price code");
        }
    }

    public double getCharge(int dayRented) {
        double result = 0;
        switch (getPriceCode()) {
            case Movie.REGULAR:
                result += 2;
                if (dayRented > 2) {
                    result += (dayRented - 2) * 1.5;
                }
                break;
            case Movie.NEW_RELEASE:
                result += dayRented * 3;
                break;
            case Movie.CHILDREN:
                result += 1.5;
                if (dayRented > 3) {
                    result += (dayRented - 3) * 1.5;
                }
                break;
        }
        return result;
    }

    public int getFrequentRenterPoints(int dayRented) {
        if ((getPriceCode() == Movie.NEW_RELEASE) && dayRented > 1) {
            return 2;
        }
        return 1;//不喜欢用else
    }
}

public abstract class Price {
    abstract int getPriceCode();
}

class ChildrensPrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.CHILDREN;
    }
}

class NewReleasePrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.NEW_RELEASE;
    }
}

class RegularPrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.REGULAR;
    }
}

 

 

11 多态取代Switch,创建price及子类

在price类加抽象函数,并在所有子类中加上对应的具体函数;

public abstract class Price {
    abstract int getPriceCode();

    abstract double getCharge(int dayRenter);
}

class ChildrensPrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.CHILDREN;
    }

    @Override
    double getCharge(int dayRented) {
        double result = 1.5;
        if (dayRented > 3) {
            result += (dayRented - 3) * 1.5;
        }
        return result;
    }
}

class NewReleasePrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.NEW_RELEASE;
    }

    @Override
    double getCharge(int dayRented) {
        return dayRented * 3;
    }
}

class RegularPrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.REGULAR;
    }

    @Override
    double getCharge(int dayRented) {
        double result = 2;
        if (dayRented > 2) {
            result += (dayRented - 2) * 1.5;
        }
        return result;
    }
}

import org.junit.Before;

public class Movie {
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;
    public static final int CHILDREN = 2;

    private String title;
    private int priceCode;
    private Price price;

    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 price.getPriceCode();
    }

    public void setPriceCode(int priceCode) {
        switch (priceCode) {
            case REGULAR:
                price = new RegularPrice();
                break;
            case CHILDREN:
                price = new ChildrensPrice();
                break;
            case NEW_RELEASE:
                price = new NewReleasePrice();
                break;
            default:
                throw new IllegalArgumentException("Incorrect price code");
        }
    }

    public double getCharge(int dayRented) {
        return price.getCharge(dayRented);
    }

    public int getFrequentRenterPoints(int dayRented) {
        if ((getPriceCode() == Movie.NEW_RELEASE) && dayRented > 1) {
            return 2;
        }
        return 1;//不喜欢用else
    }
}

 

 

12 继续修改晚上其他几个函数

public abstract class Price {
    abstract int getPriceCode();

    abstract double getCharge(int dayRenter);

    public int getFrequentRenterPoints(int dayRented) {
        return 1;
    }
}

class ChildrensPrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.CHILDREN;
    }

    @Override
    double getCharge(int dayRented) {
        double result = 1.5;
        if (dayRented > 3) {
            result += (dayRented - 3) * 1.5;
        }
        return result;
    }
}

class NewReleasePrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.NEW_RELEASE;
    }

    @Override
    double getCharge(int dayRented) {
        return dayRented * 3;
    }

    public int getFrequentRenterPoints(int dayRented) {
        return (dayRented > 1) ? 2 : 1;
    }
}

class RegularPrice extends Price {
    @Override
    int getPriceCode() {
        return Movie.REGULAR;
    }

    @Override
    double getCharge(int dayRented) {
        double result = 2;
        if (dayRented > 2) {
            result += (dayRented - 2) * 1.5;
        }
        return result;
    }
}

import org.junit.Before;

public class Movie {
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;
    public static final int CHILDREN = 2;

    private String title;
    private int priceCode;
    private Price price;

    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 price.getPriceCode();
    }

    public void setPriceCode(int priceCode) {
        switch (priceCode) {
            case REGULAR:
                price = new RegularPrice();
                break;
            case CHILDREN:
                price = new ChildrensPrice();
                break;
            case NEW_RELEASE:
                price = new NewReleasePrice();
                break;
            default:
                throw new IllegalArgumentException("Incorrect price code");
        }
    }

    public double getCharge(int dayRented) {
        return price.getCharge(dayRented);
    }

    public int getFrequentRenterPoints(int dayRented) {
        return price.getFrequentRenterPoints(dayRented);
    }
}