讀書筆記 | 重構(gòu)第一章第一個(gè)案例

原始代碼:

Customer類

package char1.version01;

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

public class Customer {
    private String _name;
    private Vector _rentals = new Vector<>();

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

    public void addRental(Rental arg) {
        _rentals.addElement(arg);
    }

    public String getName() {
        return _name;
    }

    public String statement() {
        double totalAmount = 0;
        int frequentRenterPoints = 0;
        Enumeration rentals = _rentals.elements();
        String result = "Rental Record for" + getName() + "\n";
        while (rentals.hasMoreElements()) {
            double thisAmout = 0;
            Rental each = (Rental) rentals.nextElement();

            //
            switch (each.get_movie().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.CHILDRENS:
                    thisAmout += 1.5;
                    if (each.getDaysRented() > 3) {
                        thisAmout += (each.getDaysRented() - 3) * 1.5;
                    }
                    break;
            }
            // 加積分
            frequentRenterPoints++;
            //
            if ((each.get_movie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) {
                frequentRenterPoints++;
            }
            result += " " + each.get_movie().getTitle() + "\t" + String.valueOf(thisAmout) + "\n";
            totalAmount += thisAmout;
        }
        // footer lines
        result += "Amount owed is " + String.valueOf(totalAmount) + "\n";
        result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points";
        return result;

    }
}

Movie 類

package char1.version01;

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 int _priceCode;

    // 構(gòu)造函數(shù)
    public Movie(String title, int priceCode) {
        _title = title;
        _priceCode = priceCode;
    }

    public int getPriceCode() {
        return _priceCode;
    }

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

    public String getTitle() {
        return _title;
    }

}

Rental 類

package char1.version01;

public class Rental {
    private  Movie _movie;
    private  int _daysRented;

    public Rental(Movie _movie, int _daysRented) {
        this._movie = _movie;
        this._daysRented = _daysRented;
    }

    public Movie get_movie() {
        return _movie;
    }

    public Rental set_movie(Movie _movie) {
        this._movie = _movie;
        return this;
    }

    public int getDaysRented() {
        return _daysRented;
    }

    public Rental setDaysRented(int _daysRented) {
        this._daysRented = _daysRented;
        return this;
    }
}

測(cè)試類:

package char1.version01;

public class Test {

    public static void main(String[] args) {
        Customer c = new Customer("zhangs");
        // 常規(guī)0 兒童2 新1
        Movie movie0 = new Movie("Love",0);
        Movie movie1 = new Movie("NEW",1);
        Movie movie2 = new Movie("CHILD",2);

        Rental rental1 = new Rental(movie0,4);
        Rental rental2 = new Rental(movie1,5);
        Rental rental3 = new Rental(movie2,6);

        c.addRental(rental1);
        c.addRental(rental2);
        c.addRental(rental3);

        System.out.println(c.getName());
        System.out.println(c.statement());
    }
}


重構(gòu)后的代碼

Customer 類

package char1.version04;

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

public class Customer {
    private String _name;
    private Vector _rentals = new Vector<>();

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

    public void addRental(Rental arg) {
        _rentals.addElement(arg);
    }

    public String getName() {
        return _name;
    }

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

            Rental each = (Rental) rentals.nextElement();
            result += " " + each.get_movie().getTitle() + "\t" + each.getCharge() + "\n";
        }
        result += "Amount owed is " + getTotalCharge() + "\n";
        result += "You earned " + getTotalFrequentRenterPoints() + " frequent renter points";
        return result;

    }

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

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


Movie 類

package char1.version04;

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 int _priceCode;
    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 ChildrenPrice();
                break;
            case NEW_RELEASE:
                _price = new NewReleasePrice();
                break;
            default:
                throw new IllegalArgumentException("Incorrect Price Code");
        }
    }

    public String getTitle() {
        return _title;
    }


    double getCharge(int dayRented) {

        return _price.getCharge(dayRented);
    }

    int getFrequentRenterPoints(int daysRented) {

        return _price.getFrequentRenterPoints(daysRented);
    }

}

Price 類

package char1.version04;


abstract class Price {
    abstract int getPriceCode();

    abstract double getCharge(int dayRented);

    int getFrequentRenterPoints(int daysRented) {
        return 1;
    }
}

class ChildrenPrice extends Price {
    int getPriceCode() {
        return Movie.CHILDRENS;
    }

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

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

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

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


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

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

Rental 類

package char1.version04;

public class Rental {
    private Movie _movie;
    private int _daysRented;

    public Rental(Movie _movie, int _daysRented) {
        this._movie = _movie;
        this._daysRented = _daysRented;
    }

    public Movie get_movie() {
        return _movie;
    }

    public Rental set_movie(Movie _movie) {
        this._movie = _movie;
        return this;
    }

    public int getDaysRented() {
        return _daysRented;
    }

    public Rental setDaysRented(int _daysRented) {
        this._daysRented = _daysRented;
        return this;
    }

    double getCharge() {

        return _movie.getCharge(_daysRented);
    }

    int getFrequentRenterPoints() {
        return _movie.getFrequentRenterPoints(_daysRented);
    }
}

測(cè)試類不用改蒂秘。

  • 如果你發(fā)現(xiàn)自己需要為程序添加一個(gè)新特性,而代碼結(jié)構(gòu)使你無法很方便地達(dá)成目的,那就先重構(gòu)那個(gè)程序裆悄,使特性的添加比較容易囱井,然后再添加特性蝉娜。

  • 重構(gòu)前馏予,先檢查自己是否有一套可靠的測(cè)試機(jī)制乐尊。這些測(cè)試必須有自我檢驗(yàn)的能力雳刺。

  • 重構(gòu)技術(shù)就是以微小的步伐修改程序劫灶,如果你犯下錯(cuò)誤,很容易便可以發(fā)現(xiàn)它掖桦。

  • 任何一個(gè)傻瓜都能寫出計(jì)算機(jī)可以理解的代碼本昏。唯有寫出人類容易理解的代碼,才是優(yōu)秀的程序員枪汪。
    (把自己的理解嵌入代碼中涌穆,這樣才不會(huì)遺忘我曾經(jīng)理解的東西)

這個(gè)例子中用到的重構(gòu)方法:

  • Extract Method 提取方法
  • Move Method 移動(dòng)方法
  • Replace Conditional With Polymorphism 用多態(tài)替代條件表達(dá)式
  • Replace Type Code with State/Strategy 用狀態(tài)/策略設(shè)計(jì)模式代替類型代碼
  • Replace Temp with Query 用查詢替換臨時(shí)變量
  • ……
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市雀久,隨后出現(xiàn)的幾起案子宿稀,更是在濱河造成了極大的恐慌,老刑警劉巖赖捌,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祝沸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡越庇,警方通過查閱死者的電腦和手機(jī)罩锐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卤唉,“玉大人涩惑,你說我怎么就攤上這事∩G” “怎么了竭恬?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵跛蛋,是天一觀的道長。 經(jīng)常有香客問我痊硕,道長问芬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任寿桨,我火速辦了婚禮,結(jié)果婚禮上强戴,老公的妹妹穿的比我還像新娘亭螟。我一直安慰自己,他們只是感情好骑歹,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布预烙。 她就那樣靜靜地躺著,像睡著了一般道媚。 火紅的嫁衣襯著肌膚如雪扁掸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天最域,我揣著相機(jī)與錄音谴分,去河邊找鬼。 笑死镀脂,一個(gè)胖子當(dāng)著我的面吹牛牺蹄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播薄翅,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼沙兰,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了翘魄?” 一聲冷哼從身側(cè)響起鼎天,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎暑竟,沒想到半個(gè)月后斋射,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡但荤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年绩鸣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纱兑。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呀闻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出潜慎,到底是詐尸還是另有隱情捡多,我是刑警寧澤蓖康,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站垒手,受9級(jí)特大地震影響蒜焊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜科贬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一泳梆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧榜掌,春花似錦优妙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胞皱,卻和暖如春邪意,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背反砌。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工雾鬼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宴树。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓呆贿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親森渐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子做入,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348