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

  • 相关阅读:
    Jquery源码分析(一)
    Lazyload 延迟加载效果
    20100128
    Linux共享库(so)动态加载和升级
    shell 数组
    Git常用命令解说
    linux shell 数组建立及使用技巧
    linux下查看用户及用户组的方法
    Zypper 用法
    linux shell 数组的长度计算、修改、循环输出等操作
  • 原文地址:https://www.cnblogs.com/5iedu/p/5916887.html
Copyright © 2020-2023  润新知