重構,第一個案例
阿新 • • 發佈:2019-03-05
第一步 bee endif 無法 分享 ace 消費 pre 金額
一、租賃程序
一個簡單的影片租賃程序,計算每一個位顧客的消費金額並打印詳單。
顧客租了哪些影片、租期多長,程序便更具租賃時間和影片類型算出費用。
影片分為三類:普通片、兒童片和新片。
除了計算費用,還要為常客計算積分,積分會根據租片種類是否為新片而不同
程序內容:
movie類:
/* movie.h */ #ifndef MOVIE_H #define MOVIE_H #include <iostream> #include <string> class Movie { public: Movie(std::stringmovie類title = "empty", int price = 0); int getPriceCode(); void setPriceCode(int arg); std::string getTitle(); static const int REGULAR; //普通影片 static const int NEW_RELEASE; //新片 static const int CHILDRENS; //兒童影片 private: std::string _title; //影片名 int _priceCode; //價格碼 }; #endif // MOVIE_H /* movie.cpp */ #include "movie.h" const int REGULAR = 0; //普通影片 const int NEW_RELEASE = 1; //新片 const int CHILDRENS = 2; //兒童影片 Movie::Movie(std::__cxx11::string title, int price) :_title(title), _priceCode(price) { }int Movie::getPriceCode() { return _priceCode; } void Movie::setPriceCode(int arg) { _priceCode = arg; } std::__cxx11::string Movie::getTitle() { return _title; }
rental類:
/* rental.h */ #ifndef RENTAL_H #define RENTAL_H #include "movie.h" class Rental { public: Rental(Movie movie, int daysRented); int getDaysRented(); Movie getMovie(); private: Movie _movie; //租賃的影片 int _daysRented; //租期 }; #endif // RENTAL_H /* rental.cpp */ #include "rental.h" Rental::Rental(Movie movie, int daysRented) { _movie = movie; _daysRented = daysRented; } int Rental::getDaysRented() { return _daysRented; } Movie Rental::getMovie() { return _movie; }Rental類
customer類:
/* customer.h */ #ifndef CUSTOMER_H #define CUSTOMER_H #include <string> #include <iostream> #include <vector> #include "movie.h" #include "rental.h" class Customer { public: Customer(std::string name); void addRental(Rental arg); std::string getName(); std::string statement(); std::vector<Rental>& getRentals(); private: std::string _name; //顧客名 std::vector<Rental> _rentals; //租賃列表 }; #endif // CUSTOMER_H /* customer.cpp */ #include "customer.h" Customer::Customer(std::__cxx11::string name) { _name = name; } void Customer::addRental(Rental arg) { _rentals.push_back(arg); } std::__cxx11::string Customer::getName() { return _name; } std::__cxx11::string Customer::statement() { double totalAmount = 0; //總金額 int frequentRenterPoints = 0; //積分點 std::string result = "Rental Record for " + getName() + "\n"; std::vector<Rental>::iterator iter = _rentals.begin(); for(;iter != _rentals.end();++iter) { double thisAmount = 0; //當前單個租賃金額 Rental each = *iter; switch(each.getMovie().getPriceCode()) { case 0: //普通片,起步價為2元,租期超過2天的部分每天1.5元 thisAmount += 2; if(each.getDaysRented() > 2) thisAmount += (each.getDaysRented() - 2) * 1.5; break; case 1: //新片,每天3元 thisAmount += each.getDaysRented() * 3; break; case 2: //兒童片,起步價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() == 1) && each.getDaysRented() > 1) { frequentRenterPoints++; } //添加詳單 result += "\t" + each.getMovie().getTitle() + "\t" + std::to_string(thisAmount) + "\n"; totalAmount += thisAmount; } //添加腳註 result += "Amount owed is " + std::to_string(totalAmount) + "\n"; result += "You earned " + std::to_string(frequentRenterPoints) + " frequent renter points" +"\n"; return result; } std::vector<Rental> &Customer::getRentals() { return _rentals; }Customer類
main程序:
#include <iostream> #include <string> #include <vector> #include "movie.h" #include "rental.h" #include "customer.h" using namespace std; int main() { /* create 10 movies */ std::vector<Movie> movies; for(int i=0;i<10;i++) { Movie tempMovie("Movie"+std::to_string(i+1), i+1); movies.push_back(tempMovie); } /* create 5 customers */ std::vector<Customer> customers; for(int i=0;i<5;i++) { Customer tempCustomers("customer" + std::to_string(i+1)); for(int j=2*i;j<2*i+2;++j) { Movie tempMovie = movies[j]; Rental tempRent(tempMovie, i+1); tempCustomers.addRental(tempRent); } customers.push_back(tempCustomers); } //print out all movies information; const std::vector<Movie>::size_type numMovies = movies.size(); for(int i=0;i<numMovies;++i) { Movie tempMovie = movies[i]; std::cout << " the Tile of the "<<i+1 << "(" << tempMovie.getTitle() << "," << tempMovie.getPriceCode() << ")" << std::endl; } std::cout << std::endl; //print out all customers information const std::vector<Customer>::size_type numCustomers = customers.size(); for(int i=0;i<numCustomers;++i) { Customer tempCust = customers[i]; std::cout << "the " << std::to_string(i+1) << " the customer " << tempCust.getName() << " has rented these movies:" << std::endl; const std::vector<Rental>::size_type numRentals = tempCust.getRentals().size(); for(int j=0;j<numRentals;++j) { std::cout << " (" << tempCust.getRentals()[j].getMovie().getTitle() << ", " << tempCust.getRentals()[j].getDaysRented() << ")" << std::endl; } } std::cout << std::endl; for(int i=0;i<numCustomers;++i) { Customer tempCust = customers[i]; std::cout << tempCust.statement() << std::endl; } return 0; }main程序
1.2 程序評價
customer裏頭的statement()做的事情太多了,它做了很多應該其他類做的事情。
如果需要修改輸出的格式,那就需要再增加一個新的計算函數。
如果需要修改影片的分類方式,它又會影響顧客消費和常客積分。這樣程序又需要更改了。
如果發現自己需要為程序添加一個特性,代碼結構讓你無法很方便地達成目的,就先重構那個程序,讓代碼更容易添加特性。
重構前,先檢查自己是否有一套可靠的測試機制。這些測試必須可以自我檢驗。
1.3 分解和重組statement()
第一步:找出代碼的邏輯泥團並運用Extract Method
然後:找出函數內的局部變量和參數
其次:找出其中的被修改的和未被修改的。
未被修改的:用作參數
修改的:用作返回值
重構,第一個案例