Smalltalkベストプラクティス・パターンのtail

ケント・ベックのあれを後ろから読んでRubyでメモしたメモ。

このメモについて

ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集 を後ろから読んだメモです。

8. 開発例

はじめに

ファイルmoney.rb

class Money
  def initialize(amount, currency)
    @amount = amount
    @currency = currency
  end
  attr_reader :amount
  attr_reader :currency

  def to_s
    "#{self.amount} #{self.currency}"
  end
end

Workspaceはirbかな。

% irb --simple-prompt -r money
>> puts Money.new(5, :USD)
5 USD

計算

class Money
  ....
  def add(money)
    self.class.new(self.amount + money.amount, self.currency)
  end
  alias + add
end

うん。

% irb --simple-prompt -r money
>> m1 = Money.new(5, :USD)
>> m2 = Money.new(7, :USD)
>> puts m1 + m2
12 USD

よし。

>> m2 = Money.new(7, :GBP)
>> puts m1 + m2
12 USD

あれ??

MoneySum導入

class MoneySum
  def initialize(monies)
    @monies = monies
  end

  def to_s
    @monies.join(' + ')
  end
end

money.addの変更

class Money
  def add(money)
    if self.currency == money.currency
      self.class.new(self.amount + money.amount, self.currency)
    else
      MoneySum.new([self, money])
    end
  end
end

も一度。

% irb --simple-prompt -r money
>> m1 = Money.new(5, :USD)
>> m2 = Money.new(7, :GBP)
>> puts m1 + m2
5 USD + 7 GBP

うん。

統合

ImpostorにするためにDouble Dispatchでかっこよくする。

money.add_moneyの追加。

class Money
  ...
  def add_money(money)
    if self.currency == money.currency
      self.class.new(self.amount + money.amount, self.currency)
    else
      MoneySum.new([self, money])
    end
  end

  def add(money)
    money.add_money(self)
  end
end

money_sum.add, add_moneyの追加

class MoneySum
  ...
  attr_reader :monies   

  def add_money(money)
    self.class.new(self.monies + [money])
  end

  def add(money)
    money.add_money_sum(self)
  end
  alias + add
end
m1 = Money.new(5, :USD)

money + money_sum ができたっぽい。

% irb --simple-prompt -r money
>> m1 = Money.new(5, :USD)
>> m2 = Money.new(7, :GBP)
>> puts m1 + (m2 + m1)
5 USD + 7 GBP + 5 USD

money_sum + moneyを定義します。

class Money
  ...
  def add_money_sum(money_sum)
    money_sum.add_money(self)
  end
end

うまくいくかな。

% irb --simple-prompt -r money
>> m1 = Money.new(5, :USD)
>> m2 = Money.new(7, :GBP)
>> puts m1 + m2 + m1
5 USD + 7 GBP + 5 USD

できた。

のこりはmoney_sum + money_sum。

class MoneySum
  ...
  def add_money_sum(money_sum)
    self.class.new(self.monies + money_sum.monies)
  end
end

どかな。

% irb --simple-prompt -r money
>> m1 = Money.new(5, :USD)
>> m2 = Money.new(7, :GBP)
>>  puts (m1 + m2) + (m1 + m2)
7 GBP + 5 USD + 7 GBP + 5 USD

フォーマット

Interesting Return Value

明示的に値を返すように書くのはどんなとき?

Rubyだとどんなときだろう。

明示的に返さない場合、Smalltalkではレシーバが返され、 Rubyでは最後に評価した値が返されます。

Yourself

Cascadeないからなあ。

Cascade

Rubyにはない。

Simple Enumeration Parameter

  • ブロックつきメソッドの、ブロックのパラメータの名前はどうしよう。

Smalltalkではdo:なので、パラメータの名前にeachをすすめているけど、 Rubyではeachなのよね。x, i, n? うーん。 説明的な単語を選ぶのかなあ。

みんなどうしてるんだろう。

Condition Expression