一個簡單的影片租賃程序,計算每個位顧客的消費金額並打印詳單。node
顧客租了哪些影片、租期多長,程序便更具租賃時間和影片類型算出費用。ios
影片分爲三類:普通片、兒童片和新片。git
除了計算費用,還要爲常客計算積分,積分會根據租片種類是否爲新片而不一樣github
程序內容:ide
movie類:函數
/* movie.h */ #ifndef MOVIE_H #define MOVIE_H #include <iostream> #include <string> class Movie { public: Movie(std::string 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; }
customer類:ui
/* 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; }
main程序:this
#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; }
customer裏頭的statement()作的事情太多了,它作了不少應該其餘類作的事情。url
若是須要修改輸出的格式,那就須要再增長一個新的計算函數。
若是須要修改影片的分類方式,它又會影響顧客消費和常客積分。這樣程序又須要更改了。
若是發現本身須要爲程序添加一個特性,代碼結構讓你沒法很方便地達成目的,就先重構那個程序,讓代碼更容易添加特性。
重構前,先檢查本身是否有一套可靠的測試機制。這些測試必須能夠自我檢驗。
第一步:找出代碼的邏輯泥團並運用Extract Method
而後:找出函數內的局部變量和參數
其次:找出其中的被修改的和未被修改的。
未被修改的:用做參數
修改的:用做返回值
重構技術就是以微小步伐修改程序,哪怕出了錯誤,也能方便的修改
switch語句,最好不要在另外一個對象的屬性基礎上運用switch語句。
哪怕不得不使用,也應該在對象本身的數據上使用。而不是在別人的數據上使用。
繼承方式提供可修改的分類
步驟一:針對類型代碼使用Self Encapsulate Field,確保仍和時候都經過取值函數和設值函數來訪問類型代碼。
多態中用到的變量用,取值和設值函數替代
新建Price類,提供相關行文,加上子類的對應具體函數
Movie類再也不保存_priceCode變量,而用Price對象(state模式)
一樣的手法處理getFrequentRenterPoints,可是出錯了
最後修改getFrequentRenterPoints,多態沒有很好的執行。
最後發現CPP基類函數若是沒有加virtual是不會重載的,子類依然會執行父類的函數,而不是本身的同名函數。
這一點連編譯器都沒有提示。代碼修改連接