您的位置:首页 > 其它

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

2013-07-13 17:04 609 查看

第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_H

class 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: