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 = ; //儿童片
static const int REGULAR = ; //普通片
static const int NEW_RELEASE = ;//新片 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 + "\n";
double totalAmount = ; //总租金额
int frequentReterPoints = ; //常客积分 vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
double thisAmount = ; //每片需要的租金
Rental& each = *(*iter); int priceCode = (each.getMovie()).getPriceCode();
switch(priceCode)
{
case Movie::REGULAR:
thisAmount += ; //普通片基本租金为2元
if(each.getDaysRented() > ) //超过2天的每天加1.5元
thisAmount +=(each.getDaysRented() - ) * 1.5;
break;
case Movie::NEW_RELEASE:
thisAmount += each.getDaysRented() * ; //新片的租金
break;
case Movie::CHILDRENS:
thisAmount += 1.5; //儿童片基本租金为1.5元
if(each.getDaysRented() > ) //超过3天的每天加1.5元
thisAmount +=(each.getDaysRented() - ) * 1.5;
break;
} //常客积分
++frequentReterPoints; //如果是新片且租期超过1天以上,则额外送1分积分
if ((each.getMovie().getPriceCode() == Movie::NEW_RELEASE) &&
each.getDaysRented() > ) ++frequentReterPoints; //显示每个租赁记录
ostringstream oss;
oss << thisAmount;
ret += "\t" + each.getMovie().getTitle() + "\t" +
oss.str()+ "\n"; totalAmount +=thisAmount; ++iter;
} //增加页脚注释
ostringstream oss;
oss << totalAmount;
ret += "Amount owed is " + oss.str() + "\n"; oss.str("");
oss << frequentReterPoints;
ret += "You earned " + oss.str() +"\n";
return ret;
}
}; void init(Customer& customer)
{
Movie* mv = new Movie("倚天屠龙记",Movie::REGULAR);
Rental* rt = new Rental(*mv, );
customer.addRental(rt); mv = new Movie("新水浒传",Movie::NEW_RELEASE);
rt = new Rental(*mv, );
customer.addRental(rt); mv = new Movie("喜羊羊与灰太狼",Movie::CHILDRENS);
rt = new Rental(*mv, );
customer.addRental(rt);
} int main()
{
Customer customer("SantaClaus");
init(customer); cout << customer.statement() <<endl; return ;
}
/*输出结果
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做出修改。