株式会社エス・スリー・フォー

C++/C#/VB.NETによる リファクタリング – リファクタリング後(C++)

Movie.h

#ifndef __MOVIE_H__
#define __MOVIE_H__

#include <string>

class Price;

class Movie {
public:
  enum price_code { 
    CHILDRENS = 2,
    REGULAR = 0,
    NEW_RELEASE = 1
  };

  Movie(std::string title, price_code priceCode);
 ~Movie();
  price_code getPriceCode() const;
  void setPriceCode(price_code arg);
  std::string getTitle() const;
  double getCharge(int daysRented) const;
  int getFrequentRenterPoints(int daysRented) const;

private:
  std::string _title;
  Price* _price;

};

#endif

Movie.cpp

#include <stdexcept>

#include "Movie.h"
#include "Price.h"

Movie::Movie(std::string title, price_code priceCode) 
  : _title(title), _price(0) {
  setPriceCode(priceCode);
}

Movie::~Movie() {
  delete _price;
}

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

void Movie::setPriceCode(price_code arg) {
  delete _price;
  switch ( arg ) {
  case REGULAR :
    _price = new RegularPrice();
    break;
  case CHILDRENS :
    _price = new ChildrensPrice();
    break;
  case NEW_RELEASE :
    _price = new NewReleasePrice();
    break;
  default:
    throw std::runtime_error("不正な料金コード");
  }
}

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

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

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

Rental.h

#ifndef __RENTAL_H__
#define __RENTAL_H__

#include "Movie.h"

class Rental {
public:
  Rental(Movie* movie, int daysRented);
  int getDaysRented() const;
  const Movie* getMovie() const;
  double getCharge() const;
  int getFrequentRenterPoints() const;

private:
  Movie* _movie;
  int _daysRented;

};

#endif

Rental.cpp

#include "Rental.h"

Rental::Rental(Movie* movie, int daysRented) : _movie(movie), _daysRented(daysRented) {
}

int Rental::getDaysRented() const {
  return _daysRented;
}

const Movie* Rental::getMovie() const {
  return _movie;
}

double Rental::getCharge() const {
  return _movie->getCharge(_daysRented);
}

int Rental::getFrequentRenterPoints() const {
  return _movie->getFrequentRenterPoints(_daysRented);
}

Customer.h

#ifndef __CUSTOMER_H__
#define __CUSTOMER_H__

#include <vector>
#include <string>

class Rental;

class Customer {
  friend class CustomerTest;

public:
  explicit Customer(std::string name);
  void addRental(Rental* arg);
  std::string getName() const;
  std::string statement() const;

private:
  double getTotalCharge() const;
  int getTotalFrequentRenterPoints() const;

  std::string _name;
  std::vector<Rental*> _rentals;

};

#endif

Customer.cpp

#include <sstream>

#include "Customer.h"
#include "Rental.h"
#include "Movie.h"

Customer::Customer(std::string name) : _name(name) {
}

void Customer::addRental(Rental* arg) {
  _rentals.push_back(arg);
}

std::string Customer::getName() const {
  return _name;
}

std::string Customer::statement() const {
  std::ostringstream result;
  result << "Rental Record for " << getName() << "\n";
  for ( std::vector<Rental*>::const_iterator rentals = _rentals.begin();
        rentals != _rentals.end(); ++rentals ) {
    const Rental* each = *rentals;
    // この貸し出しに対する数値の表示
    result << "\t" << each->getMovie()->getTitle() << "\t"
           <<  each->getCharge() << "\n";
  }
  // フッタ部分の追加
  result << "Amount owed is " << getTotalCharge() << "\n"
         << "You earned " << getTotalFrequentRenterPoints() << " frequent renter points";
  return result.str();
}

double Customer::getTotalCharge() const {
  double result = 0;
  for ( std::vector<Rental*>::const_iterator rentals = _rentals.begin();
        rentals != _rentals.end(); ++rentals ) {
    const Rental* each = *rentals;
    result += each->getCharge();
  }
  return result;
}

int Customer::getTotalFrequentRenterPoints() const {
  int result = 0;
  for ( std::vector<Rental*>::const_iterator rentals = _rentals.begin();
        rentals != _rentals.end(); ++rentals ) {
    const Rental* each = *rentals;
    result += each->getFrequentRenterPoints();
  }
  return result;
}

Price.h

#ifndef __PRICE_H__
#define __PRICE_H__

#include "Movie.h"

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

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

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

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

#endif

Price.cpp

#include "Price.h"

// Price

int Price::getFrequentRenterPoints(int daysRented) const {
  return 1;
}

// ChildrensPrice

Movie::price_code ChildrensPrice::getPriceCode() const {
  return Movie::CHILDRENS;
}

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

// NewReleasePrice

Movie::price_code NewReleasePrice::getPriceCode() const {
  return Movie::NEW_RELEASE;
}

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

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

// RegularPrice

Movie::price_code RegularPrice::getPriceCode() const {
  return Movie::REGULAR;
}

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