1. 启航:影片出租,计算每一位顾客的消费金额并打印清单
1.1 场景说明:
(1)影片分类规则:普通片、儿童片和新片等3类
(2)每种影片计算租金的方式。
①普通片:基本租金为2元,超过2天的部分每天加1.5元
②新片:租期*3元
③儿童片:基本租金为1.5元,超过3天的部分每天加1.5元
(3)积分的计算:每借1片,积分加1,如果是新片且租期1天以上的额外赠送1分。
【实例分析】影片出租
//第1章:重构,第1个案例 //场景:影片出租,计算每一位顾客的消费金额 /* 说明: 1. 影片分3类:普通片、儿童片和新片。 2. 每种影片计算租金的方式。 A.普通片:基本租金为2元,超过2天的部分每天加1.5元 B.新片:租期*3 C.儿童片:基本租金为1.5元,超过3天的部分每天加1.5元 3. 积分的计算:每借1片,积分加1,如果是新片且租期1天以上的额外赠送1分。 */ #include <iostream> #include <vector> #include <string> #include <sstream> using namespace std; //影片类(只是一个简单的纯数据类) class Movie { private: string title; //片名 int pricecode; //价格 public: static const int CHILDRENS = 2; //儿童片 static const int REGULAR = 0; //普通片 static const int NEW_RELEASE = 1;//新片 Movie(string title, int priceCode) { this->title = title; this->pricecode = priceCode; } string getTitle(){return title;} void setTitle(string value) { title = value; } int getPriceCode(){return pricecode;} void setPriceCode(int value) { this->pricecode = value; } }; //租赁类(表示某个顾客租了一部影片) class Rental { private: Movie& movie; //所租的影片 int daysRented; //租期 public: Rental(Movie& movie, int daysRented):movie(movie) { this->daysRented = daysRented; } int getDaysRented(){return daysRented;} Movie& getMovie() { return movie; } }; //顾客类(用来表示顾客) class Customer { private: string name; //顾客姓名 vector<Rental*> rentals; //每个租赁记录 public: Customer(string name) { this->name = name; } void addRental(Rental* value) { rentals.push_back(value); } string getName(){return name;} //statement(报表),生成租赁的详单 string statement() { string ret = "Rental Record for " + name + " "; double totalAmount = 0; //总租金额 int frequentReterPoints = 0; //常客积分 vector<Rental*>::iterator iter = rentals.begin(); while( iter != rentals.end()) { double thisAmount = 0; //每片需要的租金 Rental& each = *(*iter); int priceCode = (each.getMovie()).getPriceCode(); switch(priceCode) { case Movie::REGULAR: thisAmount += 2; //普通片基本租金为2元 if(each.getDaysRented() > 2) //超过2天的每天加1.5元 thisAmount +=(each.getDaysRented() - 2 ) * 1.5; break; case Movie::NEW_RELEASE: thisAmount += each.getDaysRented() * 3; //新片的租金 break; case Movie::CHILDRENS: thisAmount += 1.5; //儿童片基本租金为1.5元 if(each.getDaysRented() > 3) //超过3天的每天加1.5元 thisAmount +=(each.getDaysRented() - 3 ) * 1.5; break; } //常客积分 ++frequentReterPoints; //如果是新片且租期超过1天以上,则额外送1分积分 if ((each.getMovie().getPriceCode() == Movie::NEW_RELEASE) && each.getDaysRented() > 1) ++frequentReterPoints; //显示每个租赁记录 ostringstream oss; oss << thisAmount; ret += " " + each.getMovie().getTitle() + " " + oss.str()+ " "; totalAmount +=thisAmount; ++iter; } //增加页脚注释 ostringstream oss; oss << totalAmount; ret += "Amount owed is " + oss.str() + " "; oss.str(""); oss << frequentReterPoints; ret += "You earned " + oss.str() +" "; return ret; } }; void init(Customer& customer) { Movie* mv = new Movie("倚天屠龙记",Movie::REGULAR); Rental* rt = new Rental(*mv, 2); customer.addRental(rt); mv = new Movie("新水浒传",Movie::NEW_RELEASE); rt = new Rental(*mv, 3); customer.addRental(rt); mv = new Movie("喜羊羊与灰太狼",Movie::CHILDRENS); rt = new Rental(*mv, 5); customer.addRental(rt); } int main() { Customer customer("SantaClaus"); init(customer); cout << customer.statement() <<endl; return 0; } /*输出结果 Rental Record for SantaClaus 倚天屠龙记 2 新水浒传 9 喜羊羊与灰太狼 4.5 Amount owed is 15.5 You earned 4 */
1.2 存在问题
(1)报表函数(statement)太长,它做了很多原来应该由其他类完成的事情。
(2)当希望以HTML格式输出报表时,不能复用statement的任何代码,只能重新编写一个新的htmlStatement函数,然后statement复制一份并做修改。
(3)此时,如果计费标准也发生变化,必须同时修改statement和htmlStatement函数,并确保两处修改的一致性。
(4)如果用户希望改变影片分类规则,并设想了几种方案,这些方案会影响到顾客消费和常客积分的计算方式。则必须对statement做出修改。