《重构》读书笔记(二)——第一章 第一个重构案例
来源:互联网 发布:域名申请的步骤包括 编辑:程序博客网 时间: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;}
- 《重构》读书笔记(二)——第一章 第一个重构案例
- 第一章:重构,第一个案例(读书笔记系列1)
- 第一章:重构,第一个案例(读书笔记系列2)
- 第一章:重构,第一个案例(读书笔记系列3)
- 重构-改善既有代码的设计——第一章 重构,第一个案例
- 第一章 重构第一个案例
- 第一章 重构,第一个案例
- 重构第一章 重构的第一个案例
- 《重构》读书笔记(二)
- 重构,第一个案例(三)
- 重构:第一个案例
- 一、重构,第一案例
- 重构--第一个案例
- 《重构》读书笔记(二)
- 重构—改善既有代码的设计001:重构,第一个案例
- 读书笔记----App研发录 第一章 重构
- 《重构改善既有代码的设计》第一个重构案例
- 《重构》读书笔记(1)——为何重构
- NS2中文手册之链路错误模型解释
- 判断浏览器类别
- POJ 1020 DFS
- WPF-常用布局容器
- Java - Http异步工具包(HttpClient实现)
- 《重构》读书笔记(二)——第一章 第一个重构案例
- UIscrollview ios
- JAVA中数组转化成list的方法
- Linux errno 错误对照表
- NS2中无线通信距离的计算
- poj 1222 关灯开灯问题 暴搜
- Android 之 Socket通信
- org.hibernate.NonUniqueObjectException:Hibernate更新时报错处理
- smartform报表当前页/总页数