この自動販売機に投入する金額を100や500などの整数値で渡していますが、現実の自動販売機では100円や500円などの硬貨を投入します。硬貨を表す定義をenum
で定義してbuy
メソッドに硬貨以外を渡せないようにしましょう。このように型を明示することによって、間違った値を指定できなくして不具合の要因を取り除くことができます。例えば、VendingMachine#buy(payment, kind_of_drink)
の第一引数に510などの想定していない値を指定できなくなります。
下記コードはこちらの内容です。
class Coin
ONE_HUNDRED = 100
FIVE_HUNDRED = 500
end
硬貨と同様に、飲み物の種別も定数で定義しましょう。
class DrinkType
COKE = 1
DIET_COKE = 2
TEA = 3
end
追加した定数をテストコードで使用するようにします。
def test500円でコーラを購入
- drink = @vm.buy(500, Drink::COKE)
+ drink = @vm.buy(Coin::FIVE_HUNDRED, DrinkType::COKE)
change = @vm.refund
- assert_equal(Drink::COKE, drink.kind)
- assert_equal(400, change)
+ assert_equal(DrinkType::COKE, drink.kind)
+ assert_equal([Coin::ONE_HUNDRED] * 4, change)
end
自動販売機内の商品の在庫数を整数値で保持しています。
class VendingMachine
def initialize@quantity_of_coke = 5 # コーラの在庫数
@quantity_of_diet_coke = 5 # ダイエットコーラの在庫数
@quantity_of_tea = 5 # お茶の在庫数
この在庫数をラップするStock
クラスを用意して、VendingMachine
内で使用するようにしましょう。
class Stock
def initialize(quantity)
@quantity = quantity
end
def quantity@quantity
end
def decrement@quantity -= 1
end
end
VendingMachine
クラスでは、在庫の初期化、在庫数の確認、在庫の更新で、以下のように修正します。
class VendingMachine
def initialize# 在庫数の初期化
- @quantity_of_coke = 5 # コーラの在庫数
- @quantity_of_diet_coke = 5 # ダイエットコーラの在庫数
- @quantity_of_tea = 5 # お茶の在庫数
+ @stock_of_coke = Stock.new(5) # コーラの在庫数
+ @stock_of_diet_coke = Stock.new(5) # ダイエットコーラの在庫数
+ @stock_of_tea = Stock.new(5) # お茶の在庫数
(...省略...)
end
def buy(payment, kind_of_drink)
(...省略...)
# 在庫数の確認
- if kind_of_drink == Drink::COKE && @quantity_of_coke == 0
- @change += payment
+ if kind_of_drink == DrinkType::COKE && @stock_of_coke.quantity == 0
+ @change.push(payment)
return nil
(...省略...)
# 在庫数の更新
- if kind_of_drink == Drink::COKE
- @quantity_of_coke -= 1
- elsif kind_of_drink == Drink::DIET_COKE then
- @quantity_of_diet_coke -= 1
+ if kind_of_drink == DrinkType::COKE
+ @stock_of_coke.decrement
+ elsif kind_of_drink == DrinkType::DIET_COKE then
+ @stock_of_diet_coke.decrement
else
- @quantity_of_tea -= 1
+ @stock_of_tea.decrement
end
意味のある値に対して型を定義することで、コードの可読性を高め、変更に強くし、拡張しやすくなります。一般的にValueObject
と呼ばれるテクニックで以下の特徴を持ちます。