第1章 重构,第一个案例(1):糟糕的statement函数设计

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做出修改。

原文地址:https://www.cnblogs.com/5iedu/p/5916887.html