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

    我们继续重构,接下来我们遇到的问题是switch语句,书上说最好不要在另一个对象的属性基础上运用switch语句。如果不得不使用,也应该在对象自己的数据上使用而不是在别人的对象上使用。

    我们看到Rental的getCharge()里边的switch语句中的选择条件是getMovie().getPriceCode(),所以我们需要将getCharge()放到Movie类中。

    下边是新增加的Movie中的getCharge()和修改过的Rental中的getCharge():

    // method in Movie
    public double getCharge(int daysRented)
    {
    double result = 0;
    // determine amounts for each line
    switch(getPriceCode())
    {
    case Movie.REGULAR:
    result += 2;
    if(daysRented > 2)
    {
    result += (daysRented - 2) * 1.5;
    }
    break;

    case Movie.NEW_RELEASE:
    result += daysRented * 3;
    break;

    case Movie.CHILDRENS:
    result += 1.5;
    if(daysRented > 3)
    {
    result += (daysRented - 3) * 1.5;
    }
    break;
    }

    return result;
    }
    // Method in Rental
    public double getCharge()
    {
    return _movie.getCharge(_daysRented);
    }

    之后,我们继续重构,我们以相同的方法处理常客积分的计算,这样我们就把根据影片类型而变化的所有东西都放到了Movie类中。

    // Movie中增加的函数
    public int getFrequentRenterPoints(int daysRented)
    {
    if((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)
    {
    return 2;
    }
    else
    {
    return 1;
    }
    }
    // Rental中修改的函数
    public int getFrequentRentalPoints()
    {
    return _movie.getFrequentRenterPoints(_daysRented);
    }

    继续重构,我们来到了继承。

    我们有数种影片类型,它们以不同的方式回答相同的问题。这听起来很像子类的工作。我们可以建立Movie的三个子类,每个子类都有自己的计算方法。

    下边是UML图

    继续重构:

    首先我们使用Replace Type Code WithState/Strategy,第一步骤是针对类型代码使用Self Encapsulate Field,确保任何时候都通过取值函数和设置函数来访问类型代码。

    我们直接修改Movie的构造函数:

        public Movie(String title, int priceCode)
    {
    _title = title;
    _priceCode = priceCode;
    }

    修改为:

        public Movie(String title, int priceCode)
    {
    _title = title;
    setPriceCode(priceCode);
    }

    接下来,我们需要新建4个类:

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

    @Override
    int getPriceCode()
    {
    return Movie.REGULAR;
    }

    }
    public class NewReleasePrice extends Price 
    {

    @Override
    int getPriceCode()
    {
    return Movie.NEW_RELEASE;
    }

    }
    public class ChildrensPrice extends Price 
    {

    @Override
    int getPriceCode()
    {
    return Movie.CHILDRENS;
    }

    }

    然后我们就可以使用新建的这些类了,我们需要修改Movie类中的“价格代号”访问函数,让他们使用新建的类。

    下边是修改前的样子:

        private int _priceCode;

    public int getPriceCode()
    {
    return _priceCode;
    }

    public void setPriceCode(int priceCode)
    {
    _priceCode = priceCode;
    }

    这意味着我们必须在Movie类中保存一个Price对象,而不再是保存一个_priceCode变量了,此外我们还需要修改访问函数:

        private Price _price;

    public int getPriceCode()
    {
    return _price.getPriceCode();
    }

    public void setPriceCode(int movieType)
    {
    switch(movieType)
    {
    case REGULAR:
    _price = new RegularPrice();
    break;
    case CHILDRENS:
    _price = new ChildrensPrice();
    break;
    case NEW_RELEASE:
    _price = new NewReleasePrice();
    break;
    }
    }

    接下来我们要对getCharge()进行Move Method,从Movie转移到Price中

    转移前的代码:

    // Method in Movie
    public double getCharge(int daysRented)
    {
    double result = 0;
    // determine amounts for each line
    switch(getPriceCode())
    {
    case Movie.REGULAR:
    result += 2;
    if(daysRented > 2)
    {
    result += (daysRented - 2) * 1.5;
    }
    break;

    case Movie.NEW_RELEASE:
    result += daysRented * 3;
    break;

    case Movie.CHILDRENS:
    result += 1.5;
    if(daysRented > 3)
    {
    result += (daysRented - 3) * 1.5;
    }
    break;
    }

    return result;
    }

    新的Price,ChildrenPrice,RegularPrice和NewReleasePrice类:

    public abstract class Price 
    {
    abstract int getPriceCode();
    abstract double getCharge(int daysRented);
    }
    public class ChildrensPrice extends Price 
    {

    @Override
    int getPriceCode()
    {
    return Movie.CHILDRENS;
    }

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

    }
    public class NewReleasePrice extends Price 
    {

    @Override
    int getPriceCode()
    {
    return Movie.NEW_RELEASE;
    }

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

    }
    public class RegularPrice extends Price 
    {

    @Override
    int getPriceCode()
    {
    return Movie.REGULAR;
    }

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

    }

    OK,所有的准备工作都做完了,我们来修改一下Movie的getCharge()函数:

    修改前:

        public double getCharge(int daysRented)
    {
    double result = 0;
    // determine amounts for each line
    switch(getPriceCode())
    {
    case Movie.REGULAR:
    result += 2;
    if(daysRented > 2)
    {
    result += (daysRented - 2) * 1.5;
    }
    break;

    case Movie.NEW_RELEASE:
    result += daysRented * 3;
    break;

    case Movie.CHILDRENS:
    result += 1.5;
    if(daysRented > 3)
    {
    result += (daysRented - 3) * 1.5;
    }
    break;
    }

    return result;
    }

    修改后:

        public double getCharge(int daysRented)
    {
    return _price.getCharge(daysRented);
    }

    OK,我们继续用同样的方法处理getFrequentRenterPoints()

    首先我们在Price类中添加函数:

    public abstract class Price 
    {
    abstract int getPriceCode();
    abstract double getCharge(int daysRented);
    int getFrequentRenterPoints(int daysRented)
    {
    return 1;
    }
    }

    接着我们需要重写NewReleasePrice中的函数:

        @Override
    int getFrequentRenterPoints(int daysRented)
    {
    if(daysRented > 1)
    {
    return 2;
    }
    else
    {
    return 1;
    }
    }

    OK,做好准备我们就可以修改Movie中的getFrequentRenterPoints了

        public int getFrequentRenterPoints(int daysRented)
    {
    return _price.getFrequentRenterPoints(daysRented);
    }

    OK,我们的重构到此结束了。
















  • 相关阅读:
    echarts 实时获取数据
    js 对象与数组相互转化的快捷方法 Object.keys()、Object.values()、Object.entries()
    koa2 中使用 svg-captcha 生成验证码
    分享面试资料包
    8位单片机中一个容易被忽视的溢出问题
    献给半夜加班到深夜的女程序员
    java调用WebService接口方法
    算法小记:快速排序
    STL源码剖析 迭代器(iterator)概念与编程技法(三)
    [置顶] 蓝牙基础知识进阶——Physical channel
  • 原文地址:https://www.cnblogs.com/xiaobo68688/p/2316460.html
Copyright © 2011-2022 走看看