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

该博客通过分析影片租赁店系统代码,展示了如何进行重构以提高代码设计的合理性。作者首先介绍了代码的基本结构,包括Movie、Rental和Customer类,然后指出了现有设计的隐患,如代码重复和高耦合。接下来,通过提取方法、明确模块职责和运用多态,逐步改进了代码,降低了类之间的耦合,提高了可维护性和扩展性。最后,提出了重构后的设计,利用Price接口和其子类实现状态模式,使得影片类型的变化更加灵活。
案例描述如下:
1.影片租赁店目前提供普通影片,新片,儿童影片三种类型影片供顾客租赁,不同影片类型拥有不同价格码
2.计费规则按照影片类型和租期有所不同
3.提供常客积分制度,积分对影片类型和租期有一定要求
要求:计算顾客的消费金额并打印租赁详单
Movie(影片)
/**
 * 影片类,分为不同类型价格不同
 *
 * @author lune
 * @create 2017-11-14 17:40
 */
public class Movie {
    public static final int REGULAR = 0;            //普通影片
    public static final int NEW_RELEASE = 1;        //新片
    public static final int CHILDRENS = 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 int getPriceCode() {
        return priceCode;
    }

    public void setPriceCode(int priceCode) {
        this.priceCode = priceCode;
    }
}
Rental(租赁)
/**
 * 租赁类,用于绑定某个顾客租赁的影片,包含影片名和租期
 *
 * @author lune
 * @create 2017-11-14 17:35
 */
public class Rental {
    private Movie movie;              //租赁的影片
    private int daysRented;           //租期

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

    public Movie getMovie() {
        return movie;
    }

    public int getDaysRented() {
        return daysRented;
    }
}
Customer(顾客)
/**
 * 顾客类,可进行多种租赁,需要打印详单
 *
 * @author lune
 * @create 2017-11-14 17:35
 */
public class Customer {
    private String name;           //顾客名
    private Vector rentals = new Vector();  //租赁列表

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

    public String getName() {
        return name;
    }

    //添加租赁信息
    public void addRental(Rental rental) {
        rentals.addElement(rental);
    }

    //打印详单方法
    public String statement() {
        double totalAmount = 0;     //总金额
        int frequentRenterPoints = 0;  //积分点
        Enumeration items = rentals.elements(); //用户所有租赁列表
        String result = getName() + " 的租赁详单如下 :" + "\n";
        //循环遍历租赁影片,计算消费金额
        while (items.hasMoreElements()) {
            double thisAmount = 0;  //当前单个租赁金额
            Rental each = (Rental) items.nextElement();

            //租赁计费规则
            switch (each.getMovie().getPriceCode()) {
                case Movie.REGULAR:   //普通片,起步价为2元,租期超过2天的部分每天1.5元
                    thisAmount += 2;
                    if (each.getDaysRented() > 2)
                        thisAmount += (each.getDaysRented() - 2) * 1.5;
                    break;
                case Movie.NEW_RELEASE: //新片,每天3元
                    thisAmount += each.getDaysRented() * 3;
                    break;
                case Movie.CHILDRENS:  //儿童片,起步价1.5元,租期超过3天的部分每天1.5元
                    thisAmount += 1.5;
                    if (each.getDaysRented() > 3)
                        thisAmount += (each.getDaysRented() - 3) * 1.5;
                    break;
            }
            frequentRenterPoints++;     //每借一张加1个积分点
            //积分累加条件:新版本的片子,借的时间大于1天
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)
                    && each.getDaysRented() > 1) {
                frequentRenterPoints++;
            }
            //添加详单
            result += "\t" + each.getMovie().getTitle() + "\t" +
                    "\t"
                    + String.valueOf(thisAmount) + 
重构(名词):对软件内部结构的种调整,目的是在不改变"软件之可察行为"前提下,提高其可理解性,降低其修改成本.重构(动词):使用系列重构准则(手法),在不改变"软件之可察行为"前提下,调整其结构. 两种定义都强调是在不改变"软件的外部行为"前提下,不改变"软件之可察行为"就是说让修改不影响外部使用程序(程序员),在个外部来看,程序的行为和结果没有任何的变化.重构只是对程序内部结构进行调整,让代码更加容易理解,然后更容易维护. 本清晰地揭示了重构的过程,解释了重构的原理和最佳实践方式,并给出了何时以及何地应该开始挖掘代码以求改善。 章节列表如下: 目录 第1章 重构,第案例1 1.1 起点1 1.2 重构的第步7 1.3 分解并重组statement()8 1.4 运用多态取代与价格相关的条件逻辑34 1.5 结语52 第2章 重构原则53 2.1 何谓重构53 2.2 为何重构55 2.3 何时重构57 2.4 怎么对经理说60 2.5 重构的难题62 2.6 重构设计66 2.7 重构与性能69 2.8 重构起源何处71 第3章 代码的坏味道75 3.1 DuplicatedCode(重复代码)76 3.2 LongMethod(过长函数)76 3.3 LargeClass(过大的类)78 3.4 LongParameterList(过长参数列)78 3.5 DivergentChange(发散式变化)79 3.6 ShotgunSurgery(霰弹式修改)80 3.7 FeatureEnvy(依恋情结)80 3.8 DataClumps(数据泥团)81 3.9 PrimitiveObsession(基本类型偏执)81 3.10 SwitchStatements(switch惊悚现身)82 3.11 ParallelInheritanceHierarchies(平行继承体系)83 3.12 LazyClass(冗赘类)83 3.13 SpeculativeGenerality(夸夸其谈未来性)83 3.14 TemporaryField(令人迷惑的暂时字段)84 3.15 MessageChains(过度耦合的消息链)84 3.16 MiddleMan(中间人)85 3.17 InappropriateIntimacy(狎昵关系)85 3.18 AlternativeClasseswithDifferentInterfaces(异曲同工的类)85 3.19 IncompleteLibraryClass(不完美的库类)86 3.20 DataClass(纯稚的数据类)86 3.21 RefusedBequest(被拒绝的遗赠)87 3.22 Comments(过多的注释)87 第4章 构筑测试体系89 4.1 自测试代码的价值89 4.2 JUnit测试框架91 4.3 添加更多测试97 第5章 重构列表103 5.1 重构的记录格式103 5.2 寻找引用点105 5.3 这些重构手法有多成熟106 第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 IntroduceExplainingVariable(引入解释性变量)124 6.6 SplitTemporaryVariable(分解临时变量)128 6.7 RemoveAssignmentstoParameters(移除对参数的赋值)131 6.8 ReplaceMethodwithMethodObject(以函数对象取代函数)135 6.9 SubstituteAlgorithm(替换算法)139 第7章 在对象之间搬移特性141 7.1 MoveMethod(搬移函数)142 7.2 MoveField(搬移字段)146 7.3 ExtractClass(提炼类)149 7.4 InlineClass(将类内联化)154 7.5 HideDelegate(隐藏“委托关系”)157 7.6 RemoveMiddleMan(移除中间人)160 7.7 IntroduceForeignMethod(引入外加函数)162 7.8 IntroduceLocalExtension(引入本地扩展)164 第8章 重新组织数据169 8.1 SelfEncapsulateField(自封装字段)171 8.2 ReplaceDataValuewithObject(以对象取代数据值)175 8.3 ChangeValuetoReferen
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值