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()); } }