1. 仕様
顧客が借りたビデオのレンタル料金を計算して計算書を印刷する。
-
ビデオレンタルの料金を計算して計算書を印刷するプログラム
-
システムにはどの映画を何日間借りるかが入力される。
-
貸出の日数によって料金が計算され、映画の分類が判定される。
-
映画の分類は3つある。一般向け、子供向け、新作。
-
レンタルポイントも印刷される。新作かどうかによってポイント計算の仕方が異なる。
2. 設計
2.1. TODOリスト
-
✓ スモークテスト作成
-
✓ statementメソッドの分割、再配置
-
✓ amountForメソッドの移動
-
✓ レンタルポイント計算部分の抽出
-
✓ 一時変数の削除
-
✓ 料金計算の条件文をポリモーフィズムに置き換える
2.2. ユースケース図
2.3. クラス図
2.4. シーケンス図
3. 開発
3.1. Price.java
package rental.domain;
abstract class Price {
abstract int getPriceCode();
abstract int getCharge(int daysRented);
int getFrequentRenterPoints(int daysRented) {
return 1;
}
}
3.2. RegularPrice.java
package rental.domain;
public class RegularPrice extends Price {
@Override
int getPriceCode() {
return Movie.REGULAR;
}
int getCharge(int daysRented) {
int result = 200;
if (daysRented > 2) result += (daysRented - 2) * 150;
return result;
}
}
3.3. ChildrenPrice.java
package rental.domain;
public class ChildrenPrice extends Price {
@Override
int getPriceCode() {
return Movie.CHILDREN;
}
int getCharge(int daysRented) {
int result = 150;
if (daysRented > 3) result += (daysRented - 3) * 150;
return result;
}
}
3.4. NewReleasePrice.java
package rental.domain;
public class NewReleasePrice extends Price {
@Override
int getPriceCode() {
return Movie.NEW_RELEASE;
}
int getCharge(int daysRented) {
return daysRented * 300;
}
int getFrequentRenterPoints(int daysRented) {
return (daysRented > 1) ? 2 : 1;
}
}
3.5. Movie.java
package rental.domain;
public class Movie {
public static final int CHILDREN = 2;
public static final int REGULAR = 0;
public static final int NEW_RELEASE = 1;
private String _title;
private Price _price;
public Movie(String title, int priceCode) {
_title = title;
setPriceCode(priceCode);
}
public int getPriceCode() {
return _price.getPriceCode();
}
public void setPriceCode(int arg) {
switch (arg) {
case REGULAR:
_price = new RegularPrice();
break;
case CHILDREN:
_price = new ChildrenPrice();
break;
case NEW_RELEASE:
_price = new NewReleasePrice();
break;
default:
throw new IllegalArgumentException("不正な料金コード");
}
}
public String getTitle() {
return _title;
}
public int getCharge(int daysRented) {
return _price.getCharge(daysRented);
}
public int getFrequentRenterPoints(int daysRented) {
return _price.getFrequentRenterPoints(daysRented);
}
}
3.6. Rental.java
package rental.domain;
public class Rental {
Movie _movie;
private int _daysRented;
public Rental(Movie movie, int daysRented) {
_movie = movie;
_daysRented = daysRented;
}
public int getDaysRented() {
return _daysRented;
}
public Movie getMovie() {
return _movie;
}
int getCharge() {
return _movie.getCharge(_daysRented);
}
int getFrequentRenterPoints() {
return _movie.getFrequentRenterPoints(_daysRented);
}
}
3.7. Customer.java
package rental.domain;
import java.util.ArrayList;
import java.util.List;
public class Customer {
private String _name;
private List<Rental> _rentals = new ArrayList<>();
public Customer(String name) {
_name = name;
}
public void addRental(Rental arg) {
_rentals.add(arg);
}
public String getName() {
return _name;
}
public String statement() {
String result = getName() + "様のレンタル明細" + "\n";
for (Rental each : _rentals) {
//この貸し出しに関する数値の表示
result += "\t" + each.getMovie().getTitle() + "\t" + each.getCharge() + "円\n";
}
//フッタ部分の追加
result += "合計金額 " + getTotalAmount() + "円\n";
result += "獲得ポイント " + getFrequentRenterPoints() + "ポイント";
return result;
}
public String htmlStatement() {
String result = "<H1><EM>" + getName() + "</EM>様のレンタル明細</H1>\n";
for (Rental each : _rentals) {
//この貸し出しに関する数値の表示
result += each.getMovie().getTitle() + ": " + each.getCharge() + "円<BR>\n";
}
//フッタ部分の追加
result += "<P>合計金額 <EM>" + getTotalAmount() + "円</EM></P>\n";
result +=
"<P>獲得ポイント <EM>" + getFrequentRenterPoints() + "ポイント</EM></P>";
return result;
}
private int getFrequentRenterPoints() {
int frequentRenterPoints = 0;
for (Rental each : _rentals) {
frequentRenterPoints += each.getFrequentRenterPoints();
}
return frequentRenterPoints;
}
private int getTotalAmount() {
int totalAmount = 0;
for (Rental each : _rentals) {
totalAmount += each.getCharge();
}
return totalAmount;
}
}
3.8. StatementOutput.java
package rental;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import rental.domain.Customer;
import rental.domain.Movie;
import rental.domain.Rental;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class StatementOutput {
Rental newRelease;
Rental children;
Rental regular;
@BeforeEach
void setupData() {
Movie newReleaseMovie = new Movie("新作", Movie.NEW_RELEASE);
Movie childrenMovie = new Movie("子供", Movie.CHILDREN);
Movie regularMovie = new Movie("一般", Movie.REGULAR);
newRelease = new Rental(newReleaseMovie, 3);
children = new Rental(childrenMovie, 2);
regular = new Rental(regularMovie, 1);
}
String textOutput;
String htmlOutput;
@BeforeEach
void setupResult() {
textOutput =
"山田様のレンタル明細\n" +
"\t新作\t900円\n" +
"\t子供\t150円\n" +
"\t一般\t200円\n" +
"合計金額 1250円\n" +
"獲得ポイント 4ポイント";
htmlOutput =
"<H1><EM>山田</EM>様のレンタル明細</H1>\n" +
"新作: 900円<BR>\n" +
"子供: 150円<BR>\n" +
"一般: 200円<BR>\n" +
"<P>合計金額 <EM>1250円</EM></P>\n" +
"<P>獲得ポイント <EM>4ポイント</EM></P>";
}
@Test
@DisplayName("ステートメント出力")
void textOutput() {
Customer customer = new Customer("山田");
customer.addRental(newRelease);
customer.addRental(children);
customer.addRental(regular);
assertEquals(textOutput, customer.statement());
}
@Test
@DisplayName("HTMLステートメント出力")
void htmlOutput() {
Customer customer = new Customer("山田");
customer.addRental(newRelease);
customer.addRental(children);
customer.addRental(regular);
assertEquals(htmlOutput, customer.htmlStatement());
}
}