重構CH1//未重構原始碼

  1. 重構CH1//未重構原始碼
    1. 原本的程式碼

重構CH1//未重構原始碼

原文連結: https://darkblack01.blogspot.com/2012/11/blog-post_24.html
移植時的最後更新日期: 2012-11-24T20:25:06.094+08:00

重構是什麼?

《重構》的第一章表演了一段「什麼是重構?」
在這,把程式碼弄成C++,同義的表演一次。

程式規格:

  • 影片出租店用的程式
    計算每一位顧客的消費金額並列印報表(statment)
  • 操作者告訴程式    顧客租了哪些影片?
        租期多長?
    程式便計算出費用
  • 影片分為三類普通片、兒童片、新片
  • 除了計算費用,還要為常客計算點數依照「是否為新片」而所有不同

原本的程式碼

第一個類別
#include<string>

class Movie
{
std::string _title; //名稱
int _priceCode; //價格(代號)
public:
static int CHILDERNS = 2;
static int REGULAR = 0;
static int NEW_RELEASE = 1;

Moive(String title, int priceCode);
int getPriceCode();
void setPriceCode(int arg);
String getTitle();
};

inline Movie::Moive(String title, int priceCode)
{
_title = title;
_priceCode = priceCode;
}

inline int Movie::getPriceCode()
{
return _priceCode;
}

inline String Movie::getTitle()
{
return _title;
}

inline void Movie::setPriceCode()
{
_priceCode = arg;
}


第二個類別
#include "CMovie.h"

class Rental
{
Movie _movie; //影片
int _dayRented; //租期

public:
Rental(Movie movie, int dayRented);
int getDaysRented();
Movie getMovie();
};

inline Rental::Rental(Movie movie, int dayRented)
{
_movie = movie;
_dayRented = daysRented;
}

inline int Rental::getDaysRented()
{
return _dayRented;
}

inline Movie Rental::getMovie()
{
return _movie;
}



第三個類別
#include <string>
#include <vector>
#include "CRental.h"

class Customer
{
std::string _name; //姓名
std::vector _rentals; //租借

public:
Customer(std::string name);
void addRental(Rental arg);
std::string getName();
//接續下一頁
std::string statement();
};

inline Customer::Customer(std::string name)
{
_name = name;
}

inline void Customer::addRental(Rental arg)
{
_rentals.push_back(arg);
}

inline std::string Customer::getName()
{
return _name;
}

inline std::string Customer::statement()
{
double totalAmount = 0; //消費總金額
int frequentReterPoints = 0; //常客積點
std::vector::const_iterator rentals = _rentals.begin();
std::string result = "Rental Record for " + getName() + “\n”;

while(retals.hasMoreElements())
{
double thisAmount = 0;
Rental each = (Rental)rentals.next(); //取得一筆租借記錄

//determine amounts for each line
switch(each.getMovie().getPriceCode()) //取得影片出租價格
{
case Movie.REGULAR:
thisAmount += 2;
if (each.getDayRented() > 2)
thisAmount += (each.getDayRented()-2)*1.5;
break;

case Movie.NEW_RELEASE:
thisAmount += each.getDayRented()*3;
break;

case Movie.CHILDRENS:
thisAmount += 1.5;
if (each.getDayRented() > 3)
thisAmount += (each.getDayRented()-3)*1.5;
break;
}

//add frequent renter points(累加 常客積點)
frequentReterPoints++;

//add bonus for a two day new release rental
if ((each.getMovie().getPriceCode() == Movie.NEW.RELEASE) && each.getDayRented() > 1))
frequentReterPoints++;

//show figures for this rental (顯示這筆租借資料)
result += “\t” + each.getMovie().getTitle() + “\t” + std::string.valueOf(thisAmount) + “\n”;
totalAmount += thisAmount;
}

//add footer lines(結尾列印)
result += "Amount owed is " + std::string.valueOf(totalAmount) + “\n”;
rental += “You earned " + std::string.valueOf(frequentReterPoints) + " frequent renter points”;

return result;
}


理性:
差的系統→很難找到修改點→很難修改
程式設計師很容易犯錯→引入bug

感性:
不好看,不美的程式

評價:
設計得不好,不符合物件導向的精神
Quick and dirty(快速而隨性)
Customer::statement()做的事,應該是由其它class完成的

接下來
使用者希望對系統做一些修改
希望以html的格式列印報表,直接在網頁上顯示,符合潮流

困難點
根本不可能reuse目前statement()的任何行為
唯一能做的就是做一個htmlStatement(),copy-past statement()的內容再修改
若再修改,不就??

接下來
使用者希望改變影片分類規則,但是還沒決定怎麼改
設想的方案中,都會影響顧客消費和常客積點的計算方式。


所以,我們需要開始重構(待續…)