「再構築--既存コードの設計を改善する」読書ノートの5:多態置換条件論理(if/else,switch)を運用する

3424 ワード

まず「大話設計モード」&「設計モード--多重化対象ソフトウェアの基礎」のStateモードに関する章を読み終え、状態モードについて深く理解し、「再構築」の1.4節でStateモードを利用して異なる映画の価格状態を表現し続けた.
手順1:
Replace Type Code with State/Strategyを使用して、タイプに関連する動作をStateモードに移動
手順2:
Move Methodを使用してswitch文をPriceクラスに移動
手順3:
Replace Conditional with Polymorphismを使用してswitch文を削除
最終結果コード:
movie.h:
#ifndef MOVIE_H
#define MOVIE_H

#include <string>
#include "price.h"

using std::string;

class Movie
{
public:
	Movie(string title = "empty", int priceCode = 0);
	double getCharge(int daysRented);
	int getFrequentRenterPoints(int daysRented);
	int getPriceCode();
	void setPriceCode(int arg);
	string getTitle();

public:
	static const int REGULAR;
	static const int NEW_RELEASE;
	static const int CHILDRENS;

private:
	string _title;
	Price* _price;
};

#endif //MOVIE_H

movie.cpp:
#include "movie.h"

#include <iostream>
using namespace std;

const int Movie::REGULAR = 0;
const int Movie::NEW_RELEASE = 1;
const int Movie::CHILDRENS = 2;

Movie::Movie(string title , int priceCode)
{
	_title = title;
	setPriceCode(priceCode);
}

double Movie::getCharge(int daysRented)
{
	return _price->getCharge(daysRented);
}

int Movie::getFrequentRenterPoints(int daysRented) 
{
	return _price->getFrequentRenterPoints(daysRented);
}

int Movie::getPriceCode()
{
	return _price->getPriceCode();
}

void Movie::setPriceCode(int arg)
{
	switch(arg)
	{
	case REGULAR:
		_price = new RegularPrice();
		break;
	case CHILDRENS:
		_price = new ChildrensPrice();
	case NEW_RELEASE:
		_price = new NewReleasePrice();
		break;
	default:
		cerr << "Incorrect Price Code" << endl;
	}
}

string Movie::getTitle()
{
	return _title;
}

price.h:
#ifndef PRICE_H
#define PRICE_H

class Price
{
public:
	virtual int getPriceCode() = 0;
	virtual double getCharge(int daysRented) = 0;
	virtual int getFrequentRenterPoints(int daysRented);
};

class ChildrensPrice : public Price
{
public:
	virtual int getPriceCode();
	virtual double getCharge(int daysRented);
};

class NewReleasePrice : public Price
{
public:
	virtual int getPriceCode();
	virtual double getCharge(int daysRented);
	virtual int getFrequentRenterPoints(int daysRented);
};

class RegularPrice : public Price
{
public:
	virtual int getPriceCode();
	virtual double getCharge(int daysRented);
};

#endif //PRICE_H

price.cpp:
#include "price.h"
#include "movie.h"

int Price::getFrequentRenterPoints(int daysRented)
{
	if ( (getPriceCode() == Movie::NEW_RELEASE) && daysRented > 1 )	
		return 2;
	else
		return 1;
}

int ChildrensPrice::getPriceCode()
{
	return Movie::CHILDRENS;
}

double ChildrensPrice::getCharge(int daysRented)
{
	double result = 1.5;
	if (daysRented > 3)
		result += (daysRented - 3) * 1.5;

	return result;
}

int NewReleasePrice::getPriceCode()
{
	return Movie::NEW_RELEASE;
}

double NewReleasePrice::getCharge(int daysRented)
{
	return daysRented * 3;
}

int NewReleasePrice::getFrequentRenterPoints(int daysRented)
{
	return (daysRented > 1) ? 2 : 1;
}

int RegularPrice::getPriceCode()
{
	return Movie::REGULAR;
}

double RegularPrice::getCharge(int daysRented)
{
	double result = 2;
	if (daysRented > 2)
		result += (daysRented - 2) * 1.5;

	return result;
}