《重构》读书笔记(二)——第一章 第一个重构案例

来源:互联网 发布:域名申请的步骤包括 编辑:程序博客网 时间:2024/05/28 15:37

第1章 重构,第一个案例

         作者在第一章通过一个影片出租的例子,试图阐述重构的基本过程和步骤。看得出来,作者对这个案例给予厚望,花了很大的篇幅。正因如此,我没有理由不好好学习这一章。

         影片出租的例子本身不难,但我足足花了一整个下午学习了这个例子。我先是老老实实的把代码用C++重抄了一遍,然后跟着作者的步伐,一步步重构,以期体验“重构改善设计”的完美过程。

        这三个晚上尽管进展缓慢,但收获不少:

一,体验了重构改善设计的过程。

二,对state/strategy有了更进一步的理解。

三,第一次尝试使用了QTestLib对代码进行单元测试,尽管还有很多需要学习,但至少开始了。

四,关于我在开始阅读这本书时的一个疑问?我怎么样开发出我的软件功能?

        这里作者给出了答案: 我们应该学会在“重构这顶帽子”和“添加新功能这顶帽子”之间来回切换。当然,你要时刻知道自己戴的是哪一顶帽子!

         记住作者的几句忠告:

1. 任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。

2. 更改变量名称是值得的行为吗?绝对值得!!

3. 重构过程中,代码可读性 > 性能。只有在优化时,我们才需要考虑性能。

代码:

#ifndef CUSTOMER_H#define CUSTOMER_H#include <QString>#include <vector>#include "rental.h"// 顾客类class Customer{public:    Customer(const QString &name);    void apendRental(const Rental &rental);    QString getName() const;    QString statement() const;    QString htmlStatement() const;private:    QString m_name;    std::vector<Rental> m_rentals;    double getTotalAmount() const;    int getFreqRenterPoints() const;};#endif // CUSTOMER_H#include "customer.h"Customer::Customer(const QString &name)    : m_name(name){}void Customer::apendRental(const Rental &rental){    m_rentals.push_back(rental);}QString Customer::getName() const{    return m_name;}QString Customer::statement() const{    QString result = "Rental Record for " + getName() + "\n";    for (std::vector<Rental>::size_type i=0; i<m_rentals.size(); ++i)    {        Rental aRental = m_rentals.at(i);        // 添加条目信息        result += "\t" + aRental.getMovie().getTitle() + "\t" + QString::number(aRental.getCharge()) + "\n";    }    result += "TotalAmount is " + QString::number(getTotalAmount()) + "\n";    result += "FreqRenterPoints is " + QString::number(getFreqRenterPoints());    return result;}QString Customer::htmlStatement() const{    QString result = "html Rental Record for " + getName() + "\n";    for (std::vector<Rental>::size_type i=0; i<m_rentals.size(); ++i)    {        Rental aRental = m_rentals.at(i);        // 添加条目信息        result += "\t" + aRental.getMovie().getTitle() + "\t" + QString::number(aRental.getCharge()) + "\n";    }    result += "html TotalAmount is " + QString::number(getTotalAmount()) + "\n";    result += "html FreqRenterPoints is " + QString::number(getFreqRenterPoints());    return result;}double Customer::getTotalAmount() const{    double totalAmount = 0; // 金额    for (std::vector<Rental>::size_type i=0; i<m_rentals.size(); ++i)    {        Rental aRental = m_rentals.at(i);        totalAmount += aRental.getCharge();    }    return totalAmount;}int Customer::getFreqRenterPoints() const{    int freqRenterPoints = 0; // 积分    for (std::vector<Rental>::size_type i=0; i<m_rentals.size(); ++i)    {        Rental aRental = m_rentals.at(i);        freqRenterPoints += aRental.getFreqRenterPoints();    }    return freqRenterPoints;}

 

#ifndef RENTAL_H#define RENTAL_H#include "movie.h"// 租赁类class Rental{public:    Rental(const Movie &movie, int daysRented);    Movie getMovie() const;    int getDaysRented() const;    double getCharge() const;    int getFreqRenterPoints() const;private:    Movie m_movie;    int m_daysRented;};#endif // RENTAL_H #include "rental.h"Rental::Rental(const Movie &movie, int daysRented)    : m_movie(movie), m_daysRented(daysRented){}Movie Rental::getMovie() const{    return m_movie;}int Rental::getDaysRented() const{    return m_daysRented;}double Rental::getCharge() const{    return m_movie.getCharge(m_daysRented);}int Rental::getFreqRenterPoints() const{    return m_movie.getFreqRenterPoints(m_daysRented);} 

 

#ifndef MOVIE_H#define MOVIE_H#include <QString>// 影片类class Movie{public:    static const int CHILDRENS = 2;    static const int REGULAR = 0;    static const int NEWRELEASE = 1;public:    Movie(const QString &title, int priceCode);    void setTitle(const QString &title);    QString getTitle() const;    void setPriceCode(int priceCode);    int getPriceCode() const;    double getCharge(int daysRented) const;    int getFreqRenterPoints(int daysRented) const;private:    QString m_title;    int m_priceCode;};#endif // MOVIE_H #include "movie.h"Movie::Movie(const QString &title, int priceCode)    : m_title(title), m_priceCode(priceCode){}void Movie::setTitle(const QString &title){    m_title = title;}QString Movie::getTitle() const{    return m_title;}void Movie::setPriceCode(int priceCode){    m_priceCode = priceCode;}int Movie::getPriceCode() const{    return m_priceCode;}double Movie::getCharge(int daysRented) const{    double thisAmount = 0;    // 计算金额    switch (getPriceCode())    {    case REGULAR:        thisAmount += 2;        if (daysRented > 2)            thisAmount += (daysRented - 2) * 1.5;        break;    case NEWRELEASE:        thisAmount += daysRented * 3;        break;    case CHILDRENS:        thisAmount += 1.5;        if (daysRented > 3)            thisAmount += (daysRented - 3) * 1.5;        break;    default:        //assert();        break;    }    return thisAmount;}int Movie::getFreqRenterPoints(int daysRented) const{    // 计算积分    if ((m_priceCode == NEWRELEASE) && (daysRented > 1 ))    {        return 2;    }    else    {        return 1;    }}


重构至Strategy模式:

#ifndef MOVIE_H#define MOVIE_H#include <QString>class PriceStrategy;// 影片类class Movie{public:    static const int CHILDRENS = 2;    static const int REGULAR = 0;    static const int NEWRELEASE = 1;public:    Movie(const QString &title, int priceCode);    void setTitle(const QString &title);    QString getTitle() const;    void setPriceCode(int priceCode);    int getPriceCode() const;    double getCharge(int daysRented) const;    int getFreqRenterPoints(int daysRented) const;private:    QString m_title;    PriceStrategy *m_priceStrategy;};#endif // MOVIE_H#include "movie.h"#include "pricestrategy.h"Movie::Movie(const QString &title, int priceCode)    : m_title(title){    setPriceCode(priceCode);}void Movie::setTitle(const QString &title){    m_title = title;}QString Movie::getTitle() const{    return m_title;}void Movie::setPriceCode(int priceCode){    switch (priceCode)    {    case REGULAR:        m_priceStrategy = new RegularPriceStrategy();        break;    case NEWRELEASE:        m_priceStrategy = new NewReleasePriceStrategy();        break;    case CHILDRENS:        m_priceStrategy = new ChildrenPriceStrategy();        break;    default:        //assert();        break;    }}int Movie::getPriceCode() const{    return m_priceStrategy->getPriceCode();}double Movie::getCharge(int daysRented) const{    return m_priceStrategy->getCharge(daysRented);}int Movie::getFreqRenterPoints(int daysRented) const{    return m_priceStrategy->getFreqRenterPoints(daysRented);}


策略类代码文件:

#ifndef PRICESTRATEGY_H#define PRICESTRATEGY_Hclass PriceStrategy{public:    PriceStrategy();    virtual int getPriceCode() const = 0;    virtual double getCharge(int daysRented) const = 0;    virtual int getFreqRenterPoints(int daysRented) const;};class RegularPriceStrategy : public PriceStrategy{public:    RegularPriceStrategy() {}    virtual int getPriceCode() const;    virtual double getCharge(int daysRented) const;};class ChildrenPriceStrategy : public PriceStrategy{public:    ChildrenPriceStrategy() {}    virtual int getPriceCode() const;    virtual double getCharge(int daysRented) const;};class NewReleasePriceStrategy : public PriceStrategy{public:    NewReleasePriceStrategy() {}    virtual int getPriceCode() const;    virtual double getCharge(int daysRented) const;    virtual int getFreqRenterPoints(int daysRented) const;};#endif // PRICESTRATEGY_H#include "pricestrategy.h"#include "movie.h"PriceStrategy::PriceStrategy(){}int PriceStrategy::getFreqRenterPoints(int daysRented) const{    Q_UNUSED(daysRented);    return 1;}int RegularPriceStrategy::getPriceCode() const{    return Movie::REGULAR;}double RegularPriceStrategy::getCharge(int daysRented) const{    double result = 2;    if (daysRented > 2)        result += (daysRented - 2)*1.5;    return result;}int ChildrenPriceStrategy::getPriceCode() const{    return Movie::CHILDRENS;}double ChildrenPriceStrategy::getCharge(int daysRented) const{    double result = 1.5;    if (daysRented > 3)        result += (daysRented - 3)*1.5;    return result;}int NewReleasePriceStrategy::getPriceCode() const{    return Movie::NEWRELEASE;}double NewReleasePriceStrategy::getCharge(int daysRented) const{    return daysRented*3;}int NewReleasePriceStrategy::getFreqRenterPoints(int daysRented) const{    return (daysRented > 1) ? 2 : 1;}
原创粉丝点击