Part 1-8
- 構造が似ているメソッドの...
Dollar.java
Dollar times(int multiplier){
return new Dollar(amount * multiplier);
}
Franc.java
Franc times(int multiplier){
return new Franc(amount * multiplier);
}
- シグニチャを一致させる
Dollar.java
Money times(int multiplier){
return new Dollar(amount * multiplier);
}
Franc.java
Money times(int multiplier){
return new Franc(amount * multiplier);
}
- サブクラスへの直接参照を減らしたい
DollarFrancTest.java
@Test
public void testMultiplication(){
Money five = Money.dollar(5);
assertEquals(new Dollar(10),five.times(2));
assertEquals(new Dollar(15),five.times(3));
}
- Moneyにファクトリメソッドを導入し...
Money.java
static Dollar dollar(int amount){
return new Dollar(amount);
}
- Moneyを抽象クラスにしてtimesメソッドを定義する
Money.java
abstract class Money {
protected int amount;
public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount && getClass().equals(money.getClass());
}
static Money dollar(int amount){
return new Dollar(amount);
}
abstract Money times(int multiplier);
}
- テストを修正する
DollarTest.java
@Test
public void testMultiplication(){
Money five = Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}
@Test
public void testEquality(){
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertTrue(new Franc(5).equals(new Franc(5)));
assertFalse(new Franc(5).equals(new Franc(6)));
assertFalse(new Franc(5).equals(Money.dollar(5)));
}
- Francへの対応
FrancTest.java
@Test
public void testFrancMultiplication(){
Money five = Money.franc(5);
assertEquals(Money.franc(10),five.times(2));
assertEquals(Money.franc(15),five.times(3));
}
DollarTest.java
@Test
public void testMultiplication(){
Money five = Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}
@Test
public void testEquality(){
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertTrue(Money.franc(5).equals(Money.franc(5)));
assertFalse(Money.franc(5).equals(Money.franc(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
Money.java
abstract class Money {
protected int amount;
public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount && getClass().equals(money.getClass());
}
static Money dollar(int amount){
return new Dollar(amount);
}
static Money franc(int amount){
return new Franc(amount);
}
abstract Money times(int multiplier);
}
この章で行ったこと
徐々に重複を取り除いた
ファクトリメソッドを導入し、サブクラスの存在をテストから分離した
Part 1-9
通貨概念の導入
DollarFrancTest.java
@Test
public void testCurrency(){
assertEquals("USD", Money.dollar(1).currency());
assertEquals("CHF", Money.franc(1).currency());
}
- currency()の実装
Money.java
abstract String currency();
Dollar.java
class Dollar extends Money {
private String currency;
Dollar(int amount){
this.amount = amount;
currency = "USD";
}
String currency(){
return currency;
}
Money times(int multiplier){
return new Dollar(amount * multiplier);
}
}
Franc.java
class Franc extends Money{
private String currency;
Franc(int amount){
this.amount = amount;
currency = "CHF";
}
String currency(){
return currency;
}
Money times(int multiplier){
return new Franc(amount * multiplier);
}
}
- サブクラス間の重複する実装をスーパークラスに移動
Money.java
protected String currency;
String currency(){
return currency;
}
Dollar.java
class Dollar extends Money {
Dollar(int amount){
this.amount = amount;
currency = "USD";
}
Money times(int multiplier){
return new Dollar(amount * multiplier);
}
}
Franc.java
class Franc extends Money{
Franc(int amount){
this.amount = amount;
currency = "CHF";
}
Money times(int multiplier){
return new Franc(amount * multiplier);
}
}
通貨文字列をファクトリメソッドに移動し、コンストラクタを共通化したいが...
コンストラクタに引数を追加すると
Franc.java
Franc(int amount, String currency){
this.amount = amount;
this.currency = "CHF";
}
- Francをnewしているところの修正が必要
Money.java
static Money franc(int amount){
return new Franc(amount,null);
}
- ここはファクトリメソッド使うべきでは?
Franc.java
Money times(int multiplier){
return new Franc(amount * multiplier,null);
}
- timesがコンストラクタを使っていることに気づいたので、ファクトリメソッドを使うよう変更する
Franc.java
Money times(int multiplier){
return Money.franc(amount * multiplier);
}
- ファクトリメソッドが文字列を渡せるようになる
Money.java
static Money franc(int amount){
return new Franc(amount,"CHF");
}
Franc.java
Franc(int amount, String currency){
this.amount = amount;
this.currency = currency;
}
- 大きな変更を細かな変更に分割し、ミスを減らす
- Dollarに同じ変更を適用し、問題ないことを確認する
Money.java
static Money dollar(int amount){
return new Dollar(amount,"USD");
}
Dollar.java
class Dollar extends Money {
Dollar(int amount, String currency){
this.amount = amount;
this.currency = currency;
}
Money times(int multiplier){
return Money.dollar(amount * multiplier);
}
}
-
これでコンストラクタの実装が共通かできた
``` Money.javaMoney(int amount, String currency){
this.amount = amount;
this.currency = currency;
}
``` Franc.java
Franc(int amount, String currency){
super(amount,currency);
}
Dollar.java
Dollar(int amount, String currency){
super(amount,currency);
}
この章で行ったこと
コンストラクタの共通化
小さなステップでリファクタリングした
DollarTest.java
public class DollarTest {
@Test
public void testMultiplication(){
Money five = Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}
@Test
public void testEquality(){
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertTrue(Money.franc(5).equals(Money.franc(5)));
assertFalse(Money.franc(5).equals(Money.franc(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
@Test
public void testCurrency(){
assertEquals("USD", Money.dollar(1).currency());
assertEquals("CHF", Money.franc(1).currency());
}
}
FrancTest.java
public class FrancTest {
@Test
public void testFrancMultiplication(){
Money five = Money.franc(5);
assertEquals(Money.franc(10),five.times(2));
assertEquals(Money.franc(15),five.times(3));
}
}
Money.java
abstract class Money {
protected int amount;
public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount && getClass().equals(money.getClass());
}
static Money dollar(int amount){
return new Dollar(amount,"USD");
}
static Money franc(int amount){
return new Franc(amount,"CHF");
}
abstract Money times(int multiplier);
protected String currency;
String currency(){
return currency;
}
Money(int amount, String currency){
this.amount = amount;
this.currency = currency;
}
}
Dollar.java
class Dollar extends Money {
Dollar(int amount, String currency){
super(amount,currency);
}
Money times(int multiplier){
return Money.dollar(amount * multiplier);
}
}
Franc.java
pclass Franc extends Money{
Franc(int amount, String currency){
super(amount,currency);
}
Money times(int multiplier){
return Money.franc(amount * multiplier);
}
}