zoukankan      html  css  js  c++  java
  • 重构 demo篇

     本文背景为学习重构一书中的一些信息的记录。

    该篇以一个影片租赁为背景。通过一层层的重构,最终实现相对来说比较完美的代码。

    文中经典语句摘要:

    如果它没有坏,就不要动它 。” 用来形容我们工作中一些比较古董级的代码,或许写的很烂,但是基本功能是OK的,对于一个团队leader来说,不会主张你去修改他,对于一个保守级的开发来说,也懒的去修改他,虽然你个人任务修改它出错的概率近乎为0,但是仍旧是近乎。只愿我能在工作中永远保持一个敬畏之心,而非畏惧之心。

    1、第一版,较多的信息冗余在一起,相对书中的第一版已经有了一些提升,加上了个人在初步做的一些重构,怎么说哥也是写过两年代码的人。简单重构还是了解一些的。

     用户类,定义用户的名称以及租赁了哪些影片


    package
    com.woniu.refactoring; import java.util.Enumeration; import java.util.Vector; public class Customer { private String _name; private Vector _rentals = new Vector(); public String getName() { return _name; } public void setName(String _name) { this._name = _name; } public Vector getRentals() { return _rentals; } public void setRentals(Vector _rentals) { this._rentals = _rentals; } public String statement() { double totalAmout = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = "Rental Record for " + getName() + " "; while(rentals.hasMoreElements()) { double thisAmout = 0; Rental each = (Rental) rentals.nextElement(); //这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO // switch (each.getMovie().getPriceCode()) { // case Movie.REGULAR: // thisAmout += 2; // if(each.getDaysRented() > 2) { // thisAmout += (each.getDaysRented() - 2) * 1.5; // } // break; // case Movie.NEW_RELEASE: // thisAmout += each.getDaysRented() * 3; // break; // // case Movie.CHILDENS: // thisAmout += 1.5; // if(each.getDaysRented() > 3) { // thisAmout += (each.getDaysRented() - 3) * 1.5; // } // break; // } //上述方法,经过提炼后得到这个相对来说可以重用的一个函数amounFor thisAmout = amountFor(each); //这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO // frequentRenterPoints ++; // if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) { // frequentRenterPoints ++; // } //进过提炼后的积分计算方式 frequentRenterPoints = getFrequentRenterPoints(each); result += " " + each.getMovie().getTitle() + " " + String.valueOf(thisAmout) + " "; totalAmout += thisAmout; } result += "Amount owed is " + String.valueOf(totalAmout) + " "; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; return result; } /** * 用于计算此次租赁产生的积分 * @param rental 租赁 * @return */ private int getFrequentRenterPoints(Rental rental) { if((rental.getMovie().getPriceCode() == Movie.NEW_RELEASE) && rental.getDaysRented() > 1) { return 2;//这里其实在最初我是没有想到可以直接用2来代替的 } return 1; } /** * 用于计算此次租赁消费金额 * @param rental * @return */ private double amountFor(Rental rental) { double thisAmout = 0; switch (rental.getMovie().getPriceCode()) { case Movie.REGULAR: thisAmout += 2; if(rental.getDaysRented() > 2) { thisAmout += (rental.getDaysRented() - 2) * 1.5; } break; case Movie.NEW_RELEASE: thisAmout += rental.getDaysRented() * 3; break; case Movie.CHILDENS: thisAmout += 1.5; if(rental.getDaysRented() > 3) { thisAmout += (rental.getDaysRented() - 3) * 1.5; } break; } return thisAmout; } }

     影片类,定义了影片的类型以及价格

    package com.woniu.refactoring;
    
    public class Movie {
        public static final int CHILDENS = 2;
        public static final int REGULAR = 0;
        public static final int NEW_RELEASE = 1;
        
        private String _title;
        private int _priceCode;
        
        public Movie(String title, int priceCode) {
            _title = title;
            priceCode = priceCode;
        }
        
        public int getPriceCode() {
            return _priceCode;
        }
        public void setPriceCode(int _priceCode) {
            this._priceCode = _priceCode;
        }
        public String getTitle() {
            return _title;
        }
        
        
    }

     租赁类,记录影片被租赁的时间以及影片信息

    package com.woniu.refactoring;
    
    public class Rental {
        private Movie _movie;
        private int _daysRented;
        
        public Rental(Movie movie, int daysRented) {
            _movie = movie;
            _daysRented = daysRented;
        }
        
        public Movie getMovie() {
            return _movie;
        }
        public int getDaysRented() {
            return _daysRented;
        }
        
        
    }

     第二版

    由于在amountFor()方法中,并没有任何用户的信息,却在用户的类中实现了关于影片计算逻辑,金额的产生发生的位置应该是在租赁中产生的,因此,应该将其移至Rental中,使用(Move Mehtod)来进行处理。

    用户类,封装了用户总消费额以及总积分的计算。同时,将关于租赁的单价计算与单积分计算进行了迁移。

    package com.woniu.refactoring;
    
    import java.util.Enumeration;
    import java.util.Vector;
    
    public class Customer {
        private String _name;
        private Vector _rentals = new Vector();
        
        public String getName() {
            return _name;
        }
        public void setName(String _name) {
            this._name = _name;
        }
        public Vector getRentals() {
            return _rentals;
        }
        public void setRentals(Vector _rentals) {
            this._rentals = _rentals;
        }
        
        
        public String statement() {
    //        double totalAmout = 0;
    //        int frequentRenterPoints = 0;
            Enumeration rentals = _rentals.elements();
            String result = "Rental Record for " + getName() + "
    ";
            while(rentals.hasMoreElements()) {
                double thisAmout = 0;
                Rental each = (Rental) rentals.nextElement();
                //这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO
    //            switch (each.getMovie().getPriceCode()) {
    //            case Movie.REGULAR:
    //                thisAmout += 2;
    //                if(each.getDaysRented() > 2) {
    //                    thisAmout += (each.getDaysRented() - 2) * 1.5;
    //                }
    //                break;
    //            case Movie.NEW_RELEASE:
    //                thisAmout += each.getDaysRented() * 3;
    //                break;
    //
    //            case Movie.CHILDENS:
    //                thisAmout += 1.5;
    //                if(each.getDaysRented() > 3) {
    //                    thisAmout += (each.getDaysRented() - 3) * 1.5;
    //                }
    //                break;
    //            }
                //上述方法,经过提炼后得到这个相对来说可以重用的一个函数amounFor
    //            thisAmout = amountFor(each);
                thisAmout = each.getCharge();//这是第二版的重构,将金额计算与积分计算,移至了Rental中,因为这是在租赁过程中产生的
                //这里是个人阅读到这里时,认为需要重构的位置。用专业点的话叫提炼函数 TODO
    //            frequentRenterPoints ++;
    //            if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) {
    //                frequentRenterPoints ++;
    //            }
                //进过提炼后的积分计算方式
    //            frequentRenterPoints = getFrequentRenterPoints(each);
    //            frequentRenterPoints = each.getFrequentRenterPoints();//这是第二版的重构,将金额计算与积分计算,移至了Rental中,因为这是在租赁过程中产生的
                result += "	" + each.getMovie().getTitle() + "	" + String.valueOf(thisAmout) + "
    ";
    //            totalAmout += thisAmout;//2书中提到该处可以直接使用getCharge()获取金额,进而避免了局部变量的使用,但是,我没有找到关于多次计算的优化点,因此不敢王嘉苟同。
                
            }
            
            result += "Amount owed is " + String.valueOf(getTotalCharge()) + "
    ";//对于总金额计算单独提取方法,以备后用
            result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + " frequent renter points";
            return result;
        }
        
        /**
         * 获取用户消费的总金额
         * @return
         */
        private double getTotalCharge() {
            double totalAmout = 0;
            Enumeration rentals = _rentals.elements();
            while(rentals.hasMoreElements()) {
                Rental rental = (Rental)rentals.nextElement();
                totalAmout += rental.getCharge();
            }
            return totalAmout;
        }
        
        /**
         * 获取用户消费的总积分
         * @return
         */
        private int getTotalFrequentRenterPoints() {
            int result = 0;
            Enumeration rentals = _rentals.elements();
            while(rentals.hasMoreElements()) {
                Rental rental = (Rental)rentals.nextElement();
                result += rental.getFrequentRenterPoints();
            }
            return result;
        }
        
        /**
         * 用于计算此次租赁产生的积分
         * @param rental 租赁
         * @return
         */
        @Deprecated
        private int getFrequentRenterPoints(Rental rental) {
            if((rental.getMovie().getPriceCode() == Movie.NEW_RELEASE) && rental.getDaysRented() > 1) {
                return 2;//这里其实在最初我是没有想到可以直接用2来代替的
            }
            return 1;
        }
        
        /**
         * 用于计算此次租赁消费金额
         * @param rental
         * @return
         */
        @Deprecated
        private double amountFor(Rental rental) {
            return rental.getCharge();//这里其实没必要再次进行封装函数了。可以直接在循环中使用rental的getCharge方法进行计算。
    //        double thisAmout = 0;
    //        switch (rental.getMovie().getPriceCode()) {
    //        case Movie.REGULAR:
    //            thisAmout += 2;
    //            if(rental.getDaysRented() > 2) {
    //                thisAmout += (rental.getDaysRented() - 2) * 1.5;
    //            }
    //            break;
    //        case Movie.NEW_RELEASE:
    //            thisAmout += rental.getDaysRented() * 3;
    //            break;
    //
    //        case Movie.CHILDENS:
    //            thisAmout += 1.5;
    //            if(rental.getDaysRented() > 3) {
    //                thisAmout += (rental.getDaysRented() - 3) * 1.5;
    //            }
    //            break;
    //        }
    //        return thisAmout;
        }
        
    }

     租赁类,增加了关于租赁单价的计算以及积分计算。

    package com.woniu.refactoring;
    
    public class Rental {
        private Movie _movie;
        private int _daysRented;
        
        public Rental(Movie movie, int daysRented) {
            _movie = movie;
            _daysRented = daysRented;
        }
        
        public Movie getMovie() {
            return _movie;
        }
        public int getDaysRented() {
            return _daysRented;
        }
        
        /**
         * 用户此次租赁积分的计算
         * @param rental
         * @return
         */
        public int getFrequentRenterPoints() {
            if((getMovie().getPriceCode() == Movie.NEW_RELEASE) && getDaysRented() > 1) {
                return 2;//这里其实在最初我是没有想到可以直接用2来代替的
            }
            return 1;
        }
        
        
        /**
         * 用于计算此次租赁消费金额
         * 2关于这个方法,其实应该是在租赁关系发生时,已经需要计算好金额了。这样就可以避免了Customer中提到的优化点,
         * 但是,这样同样会造成如果交易取消了,我浪费资源进行了计算。
         * @param rental
         * @return
         */
        public double getCharge() {
            double thisAmout = 0;
            switch (getMovie().getPriceCode()) {
            case Movie.REGULAR:
                thisAmout += 2;
                if(getDaysRented() > 2) {
                    thisAmout += (getDaysRented() - 2) * 1.5;
                }
                break;
            case Movie.NEW_RELEASE:
                thisAmout += getDaysRented() * 3;
                break;
    
            case Movie.CHILDENS:
                thisAmout += 1.5;
                if(getDaysRented() > 3) {
                    thisAmout += (getDaysRented() - 3) * 1.5;
                }
                break;
            }
            return thisAmout;
        }
        
    }

     原本到这里,我理解,此次重构已经结束了。但发现,后续还有新的重构方向。。。。。

  • 相关阅读:
    Android开发中,有哪些让你觉得相见恨晚的方法、类或接口?
    Android实用代码七段(五)
    Android实用代码七段(四)
    Android实用代码七段(三)
    Android实用代码七段(二)
    android实用代码
    发送Notification
    按两次back键退出程序
    java常用的几种设计模式
    拍照获取图片和相册中获取图片
  • 原文地址:https://www.cnblogs.com/woniu4/p/9271532.html
Copyright © 2011-2022 走看看