《重构》读书笔记(二)——第一章 第一个重构案例
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; }
相关文章推荐
- 第一章:重构,第一个案例(读书笔记系列1)
- 第一章:重构,第一个案例(读书笔记系列2)
- 第一章:重构,第一个案例(读书笔记系列3)
- 第一个重构案例——《重构》第一章
- 第一章 重构第一个案例
- 重构第一章 重构的第一个案例
- 第一章 重构,第一个案例
- 第一章 重构,第一个案例
- 重构-改善既有代码的设计——第一章 重构,第一个案例
- 《重构--改善既有代码的设计》--重构,第一个案例(1)
- 重构,第一个案例(三)
- 《重构》读书笔记第一章
- 重构改善既有代码的设计--重构第一个案例
- 重构,第一个案例(三)
- 第1章 重构,第一个案例(3):运用多态取代switch
- 重构 第1章 重构,第一个案例
- 重构,第一个案例(三)
- 重构改善既有代码的设计--重构第一个案例
- 重构,第一个案例(三)
- 重构,第一个案例(三)