<<改善既有代码的设计>> 第1章

代码块越小,代码的功能越容易管理,代码的处理和移动也越简单。所以看到长长的代码块就要考虑是否可以把它”大卸八块”。第一步,找出”逻辑泥潭”。抽出逻辑块封装成一个方法,抽成方法的时候要注意变量的范围,被抽出方法外的被修改的变量应该要作为该方法的返回值返回。

比较之前的想法,欠缺以下的思考:
1.在A类中重构抽出的方法mA1后,没有再往下重构,应该继续思考:抽出的方法里的变量与该类的关联大吗?是否更加契合其他类(比如类B)呢?把抽出的方法mA1放到类B是否更适合呢?
2.代码量的减少不等于优化,不要总是因为恰好可共用一个循环,就把各自的逻辑都放进去(比如该方法的作用是循环输出”影片名”及其”信息”),但我会”顺便”把电影租赁”总价”和”总积分”都放到该循环里,计算完之后,取出变量,然后又各管各的进行其他逻辑。
举个栗子:

public String statement() {
        Enumeration<Rental> rentals = _rentals.elements();
        String result = "Rental Record for " + getName() + "\n";
        while (rentals.hasMoreElements()) {

            Rental each = (Rental) rentals.nextElement();

            result += "\t" + each.getMovie().getTitle() + "\t" + each.getCharge() + "\n";
        }

        result += "Amount owed is " + getTotalCharge() + "\n";
        result += "You earned " + getTotalFrequentRenterPoints() + " freequent renter points";

        return result;
    }

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

    private int getTotalFrequentRenterPoints() {
        int result = 0;
        Enumeration<Rental> rentals = _rentals.elements();
        while (rentals.hasMoreElements()) {
            Rental each = (Rental) rentals.nextElement();
            result += each.getFrequentRenterPoints();
        }
        return result;
    }

这样些逻辑确实会清晰,但如果遍历需要消耗时间大的话,还是会选择混写。
3.最重要的一点,面对多变需要扩展的业务,我们重构的目的就是要做最小、最安全、最方便的改动就能满足扩展的需求。这里用到了”states模式”,这也是我第一次接触该模式。对于设计模式还是不太了解,有些设计模式完全识别不出来。对于该模式,网上找来的总结很贴切:

1)状态模式的好处就是将于特定状态相关的行为局部化,并且将不同状态的行为分割开来。意即,将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。(2)这样做的目的是为了消除庞大的条件分支语句,大的分支判断会使得它们难以修改和扩展,状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。(3)当一个对象的行为取决于它们的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。

放上我的例子:

package example;
/**
 * @author jeff.zhan
 * @version 2016年9月27日下午7:17:04
 * 
 */
public class Movie {

    public static final int CHILDRENS = 2;
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;

    private String _title;
    private Price _price;

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

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

    public void setPriceCode(int arg) {
        switch (arg) {
        case REGULAR:
            _price = new RegularPrice();
            break;
        case CHILDRENS:
            _price = new ChildrensPrice();
            break;
        case NEW_RELEASE:
            _price = new NewReleasePrice();
            break;
        default:
            throw new IllegalArgumentException("Incorrect Price Code:" + arg);
        }
    }

    public String getTitle() {
        return _title;
    }

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

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

}
package example;
/**
 * @author jeff.zhan
 * @version 2016年9月27日下午7:17:04
 * 
 */
public class NewReleasePrice extends Price{

    @Override
    int getPriceCode() {
        // TODO Auto-generated method stub
        return Movie.NEW_RELEASE;
    }

    @Override
    double getCharge(int daysRented) {
        // TODO Auto-generated method stub
        return daysRented * 3;
    }

    @Override
    public int getFrequentRenterPoints(int daysRented) {
        // TODO Auto-generated method stub
        return (daysRented > 1) ? 2 : 1;
    }

}
package example;
/**
 * @author jeff.zhan
 * @version 2016年9月27日下午7:17:04
 * 
 */
public class RegularPrice extends Price {

    @Override
    int getPriceCode() {
        // TODO Auto-generated method stub
        return Movie.REGULAR;
    }

    @Override
    double getCharge(int daysRented) {
        // TODO Auto-generated method stub
        double result = 2;
        if (daysRented > 2) {
            result += (daysRented - 2) * 1.5;
        }
        return result;
    }

}
package example;
/**
 * @author jeff.zhan
 * @version 2016年9月27日下午7:17:04
 * 
 */
public class ChildrensPrice extends Price {

    @Override
    int getPriceCode() {
        // TODO Auto-generated method stub
        return Movie.CHILDRENS;
    }

    @Override
    double getCharge(int daysRented) {
        // TODO Auto-generated method stub
        double result = 1.5;
        if (daysRented > 3) {
            result += (daysRented - 3) * 1.5;
        }
        return result;
    }

}

总结:第3点尤为重要,这是我之前重构时候都没有考虑过得。这给了我在重构的时候多了一个新的思路。这也是代码水平好坏的很重要的一点的体现。另外关于重构,应该注重的我们当前各自的业务逻辑,如果是一个很小的无需扩展的业务逻辑,我觉得不用这么大费周章的做十分精细的重构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值