timesメソッドはかなり似ているが、完全に一致するところまではたどり着いていない。
では例えば、2つのFactory Methodをインライン化したらどうなるだろうか?
playground.swift
///Dollar子クラス
class Dollar:Money {
override init(_ amount:Int,_ currency:String){
super.init(_ :amount , _ :currency)
self.amount = amount
self.currency = currency
}
override func times(_ multiplire:Int) -> Dollar{
return Dollar(amount * multiplire, "USD")
}
}
playground.swift
///Franc子クラス
class Franc:Money {
override init(_ amount:Int, _ currency:String){
super.init(_ :amount , _ :currency)
self.amount = amount
self.currency = currency
}
override func times(_ multiplire:Int) -> Franc{
return Franc(amount * multiplire, "CHF")
}
}
でFranCクラスでは、インスタンス変数currencyは常にCHFであることがわかっている。
つまり次のように書ける。
playground.swift
///Franc子クラス
class Franc:Money {
override init(_ amount:Int, _ currency:String){
super.init(_ :amount , _ :currency)
self.amount = amount
self.currency = currency
}
override func times(_ multiplire:Int) -> Franc{
return Franc(amount * multiplire, currency)
}
}
Dollarにも適用できる。
playground.swift
///Dollar子クラス
class Dollar:Money {
override init(_ amount:Int,_ currency:String){
super.init(_ :amount , _ :currency)
self.amount = amount
self.currency = currency
}
override func times(_ multiplire:Int) -> Dollar{
return Dollar(amount * multiplire, currency)
}
}
と,ここからは考えるのではなく、コンピュータに聞いてしまおうという流れ。
優秀なソフトウェアエンジニアが10分考えて出す結論を、コンピュータなら15秒で出してしまう。
テストがなければ選択の余地はなく、慎重に検討せざるをえない。テストがあれば、試したほうが早いかどうかを選択できる。さっさとコンピュータに聞けばいい場合もある。
playground.swift
///Dollar子クラス
class Dollar:Money {
override init(_ amount:Int,_ currency:String){
super.init(_ :amount , _ :currency)
self._amount = amount
self._currency = currency
}
override func times(_ multiplire:Int) -> Money{
return Money(_amount * multiplire, _currency)
}
}
//Franc子クラス
class Franc:Money {
override init(_ amount:Int, _ currency:String){
super.init(_ :amount , _ :currency)
self._amount = amount
self._currency = currency
}
override func times(_ multiplire:Int) -> Money{
return Money(_amount * multiplire, _currency)
}
}
ここまでくると、times methodは共通化できたといっていい。
これを親クラスに移す。
で、さらなる問題はFranc型とMoney型の区別は本当に必要だろうか?という話。
本当に調べるべきは通貨が等しいかどうかであって、クラスが同じかどうかではない。
通貨の比較テストを書こう。
playground.swift
class MoneyTest{
.....
func testCurrency(){
assert("USD" == Money.dollar(1).currency())
assert("CHF" == Money.franc(1).currency())
}
func testDifferentClassEquaユユty() {
assert(Money(10, "CHF") == Money(10, "CHF"))
}
.....
playground.swift
///親クラス
class Money :Equatable{
var _amount:Int
var _currency:String
init(_ amount:Int,_ currency:String){
self._amount = amount
self._currency = currency
}
static func == (lhs: Money, rhs: Money) -> Bool {
return lhs._amount == rhs._amount &&
lhs.currency() == rhs.currency()
}
func times(_ multiplire:Int) -> Money{
return Money(_amount * multiplire, _currency)
}
func currency() -> String{
return _currency
}
func toString() -> String{
return _amount.description + " " + _currency
}
static func dollar(_ amount:Int) -> Money{
return Dollar(amount,"USD")
}
static func franc(_ amount:Int) -> Money{
return Franc(amount,"CHF")
}
}
ぜんぶのこーど
playground.swift
var moneytest = MoneyTest()
moneytest.testMultiplication()
moneytest.testEquality()
moneytest.testFrancMultiplication()
moneytest.testCurrency()
moneytest.testDifferentClassEquaユユty()
class MoneyTest{
init(){}
func testMultiplication(){
var five:Money = Money.dollar(5)
assert(Money.dollar(10) == five.times(2))
assert(Money.dollar(15) == five.times(3))
}
func testEquality(){
assert(Money.dollar(5) == Money.dollar(5))
assert(Money.dollar(6) == Money.dollar(6))
assert(Money.franc(5) == Money.franc(5))
assert(Money.franc(6) == Money.franc(6))
assert(Money.franc(6) != Money.franc(3))
assert(Money.franc(6) == Money.dollar(6))
}
func testFrancMultiplication(){
var five = Money.franc(5)
assert(Money.franc(10) == five.times(2))
assert(Money.franc(15) == five.times(3))
}
func testCurrency(){
assert("USD" == Money.dollar(1).currency())
assert("CHF" == Money.franc(1).currency())
}
func testDifferentClassEquaユユty() {
assert(Money(10, "CHF") == Money(10, "CHF"))
}
}
///親クラス
class Money :Equatable{
var _amount:Int
var _currency:String
init(_ amount:Int,_ currency:String){
self._amount = amount
self._currency = currency
}
static func == (lhs: Money, rhs: Money) -> Bool {
print(lhs.currency())
print(rhs.currency())
return lhs._amount == rhs._amount &&
lhs.currency() == rhs.currency()
}
func currency() -> String{
return _currency
}
func toString() -> String{
return _amount.description + " " + _currency
}
func times(_ multiplire:Int) -> Money{
return Money(_amount * multiplire, _currency)
}
static func dollar(_ amount:Int) -> Money{
return Dollar(amount,"USD")
}
static func franc(_ amount:Int) -> Money{
return Franc(amount,"CHF")
}
}
///Dollar子クラス
class Dollar:Money {
override init(_ amount:Int,_ currency:String){
super.init(_ :amount , _ :currency)
self._amount = amount
self._currency = currency
}
}
//Franc子クラス
class Franc:Money {
override init(_ amount:Int, _ currency:String){
super.init(_ :amount , _ :currency)
self._amount = amount
self._currency = currency
}
}