Hatena::Groupimplementationpatterns

sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java を学ぶ日記

2009-06-10

「Smalltalkベストプラクティス・パターン」増刷だそうです

| 09:06 | はてなブックマーク -  「Smalltalkベストプラクティス・パターン」増刷だそうです - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記  「Smalltalkベストプラクティス・パターン」増刷だそうです - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 のブックマークコメント


「ケント・ベックのSmalltalkベストプラクティス・パターン」増刷となりました。なぜ今頃。

http://twitter.com/umejava/status/2089622754

ともすれば忘れ去られがちな Smalltalk やそこで培われた技術や手法に、このようにして光が当たるのも、Ruby コミュニティの皆さん、特に本書のすばらしさを小まめにきちんと取り上げてくださる角谷さんの寄与がとても大きいと思います。Smalltalk ファンとしてお礼を申し上げます!


そんなわけで、SBPP本について誤植などお気づきの点がありましたら、レスください。

http://twitter.com/umejava/status/2089663871

ご協力、お願いいたします。


ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集

2007-12-02

● Getting Method, Setting Method

13:49 | はてなブックマーク - ● Getting Method, Setting Method - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 ● Getting Method, Setting Method - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 のブックマークコメント


見出しは共通ですが、主張は逆。Java [IPB95,96] では get、set をフィールド名に冠した getVarName()、setVarName(newValue) を推奨している一方で、Smalltalk [SBPP103,105] ではそうではなく、余計な my など(get、set とも読み替え可?)を付けずに単純に変数名をそのまま用いた instVarName、instVarName: を推奨しています。

なお、Smalltalk ではコロンを含めてメソッド名なので最後の : を省略してはいけないので注意してください。つまり、instVarName と instVarName: は一見、引数の有無を違えたオーバーロードに見えますが、実際のところ別のメソッドとして名前レベルで区別されます。Java では引数の有無も含めたシグネチャの違いによるオーバーロードが可能なので、おそらく Beck は当初、varName()、varName(newValue) というのを試したのでしょう。でもすぐに Java 従来の慣習に従う getVarName()、setVarName(newValue) に趣旨替えしたと、そう読めます。


あと、Smalltalk でも private なメソッドであることを主張するときに Setting Method に set を冠することがあります(get のほうはないです)。Smalltalk にはアクセスコントロール機構はないのですが、プロトコルというメソッドのカテゴライズ機構や set のような命名でユーザーにその旨を伝える慣習があるのです。



これらをうけて Ruby では、Setting Method のメソッド名の末尾に = (Smalltalk のコロンに対応)をメソッド名に含めることができるアナロジーから、SBPP での主張が対応するように思われます。


Ruby
def x
  @x
end
def x=(new_x)
  @x=new_x
end
Smalltalk
x
  ^x
x: newX
   x := newX

なにより attr_accessor はこれらアクセッサの定義を自動化してくれます。これを利用しない手はないでしょう。

class Hoge
  attr_accessor :x
end

hoge = Hoge.new
hoge.x = 4
p hoge.x   #=> 4

Geeting Method 、Setting Method は、Indirect Access[IPB47,SBPP101] と密接な関わりがあります。Beck も指摘するように、Indirect Access は柔軟性と、読みやすさやその他諸々の手間とのトレードオフです。


Ruby
# Direct Access
@x
# Indirect Access
x
Smalltalk
"Direct Access"
x
"Indirect Access"
self x

なお、メソッドコール時に Smalltalk のような self、Java のような () を省略することができる Ruby では、一見、Indirect Access がかかえる問題はすこし軽減しているように感じられます。しかし、Ruby には一時変数が同名の Getting Method を遮蔽してしまうという“落とし穴”があるので、新たにひとつ余計な注意が必要になってしまう、と考えた方がよいかも。

def x; @x end
p x   #=> nil
x = 4
p x   #=> 4
p @x   #=> nil

self や () の省略をやめればこの問題は回避できます。

def x; @x end
p x   #=> nil
x = 4
p x   #=> 4
p self.x   #=> nil
p x()   #=> nil

2007-11-29

● Safe Copy (SBPP: Enumeration Method)

13:41 | はてなブックマーク - ● Safe Copy (SBPP: Enumeration Method) - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 ● Safe Copy (SBPP: Enumeration Method) - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 のブックマークコメント

・ Safe Copy [IPB97]

コレクションを代入したインスタンス変数へのアクセスにはコピーを介しましょう。

def get_books
  result = []
  result.concat(@books)
  return result   #不要ですが、なしだと result が返るというメッセージ性に乏しいように思うので…
end

def set_books(new_books)
  @books = []
  @books.concat(new_books)
end

疑問:

#get_books は、こうではダメなのか?

def get_books
  return @books.dup.to_a   #to_a は不要ですが、result = [] と同じメッセージ性をたもせるため
end

反省:

なにげに Java の例のまま使ってしまったけれど、#get_books と #set_books は、Ruby では #books= と #books のほうが(多くの場合)ふさわしいかもわからんね。(^_^;)



・ Enumeration Method [SBPP108]

あらためて読み返してみると Safe Copy とは方向性が違いますね。ま、いっか(^_^;)。

class Department
  def employees_each(&b)
    @employees.each(&b)
  end
end

def all_employees
  result = []
  departments.each do |d|
    d.employees_each{ |e| result << e }
  end
  return result
end

@employees の要素に an Employee だけでなく、a Depertment も含む可能性がある場合。

class Depertment
  def employees_each(&b)
    @employees.each{ |e| e.employees_each(&b) }
  end
end

class Employee
  def employees_each
    yield(self)
  end
end

疑問:

Ruby では、self や括弧が省略できるので、Indirect Access [IPB47][SBPP101] のメッセージ性(可読性)がある意味、阻害されてしまうかも。たとえば、上の #depertments のコールは、@depertments のアクセスと字面がほとんど変わらず紛らわしい。かといって、Java のように getHoge/setHoge なネーミングルールを用いると #attr_accessor のうま味がなくなる。self か括弧を省略しないことで回避できるように思うが、括弧を補うよりは self を補うほうがよいのか?

def all_employees
  result = []
  self.departments.each do |d|
    d.employees_each{ |e| result << e }
  end
  return result
end
def all_employees
  result = []
  departments().each do |d|
    d.employees_each{ |e| result << e }
  end
  return result
end

メモ:

Ruby では配列がサイズ可変なので、かつ、Smalltalk の WriteStream のようなしくみがないので、writer(配列をラップして伸長可能にしたもの)を介する必要がない。


疑問:

Smalltalk で、Ruby の Array のようにサイズ可変な OrderedCollection を使ってはいけないのか?

allEmployees
    | result |
    result := OrderedCollection new.
    self departments do: [:eachDepartment |
        eachDepartment employeesDo: [:eachEmployee | result add: eachEmployee]].
    ^result asArray

速度もそんなに変わらなんしなぁ…。

| oc |
oc := OrderedCollection new.
^[1e4 timesRepeat: [oc add: #something]] timeToRun   "=> 13 "
| writer |
writer := #() writeStream.
^[1e4 timesRepeat: [writer nextPut: #something]] timeToRun   "=> 10 "

参考。

| array |
array := #().
^[1e4 timesRepeat: [array := array copyWith: #something]] timeToRun   "=> 1019 "

2007-11-27

章立てに見る両者の違い

12:27 | はてなブックマーク - 章立てに見る両者の違い - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 章立てに見る両者の違い - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 のブックマークコメント

Implementation Patterns

  • クラス
  • 状態
    • アクセス
    • 変数
    • 属性
    • パラメータ
    • 定数
    • 初期化
  • 振る舞い
    • フロー
    • メッセージ
    • 例外
  • メソッド
  • コレクション
    • メタファ
    • 論点
    • インターフェイス(SBPP: プロトコル)
    • コレクションライブラリ
    • コレクションの継承時の注意


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

  • 振る舞い
    • メソッド
    • メッセージ
  • 状態
    • インスタンス変数
    • 一時変数
  • コレクション
    • クラス
    • コレクションプロトコル
    • コレクションイディオム
  • クラス
  • フォーマット

とりあえずパターン一覧の比較

12:26 | はてなブックマーク - とりあえずパターン一覧の比較 - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 とりあえずパターン一覧の比較 - sumim が Implementation Patterns と SBPP の比較を通じて Ruby と Java  を学ぶ日記 のブックマークコメント

d:id:sumim:20071125:p1 より再掲)

● 共通・類似の内容の項目
△ Implementation Patterns のみ
▽ SBPP のみ(うち Ruby に関連ありそうな項目に [Ruby] )

クラス

△ Class
● Simple Superclass Name
● Qualified Subclass Name
△ Abstract Interface
△ Interface
△ Abstract Class
△ Versioned Interface
△ Value Object
△ Specialization
△ Subclass
△ Implementor
△ Inner Class
△ Instance-Specific Behavior
△ Conditional
● Delegation (SBPP: Delegation, Simple Delegation, Self Delegation)
● Pluggable Selector (SBPP: Pluggable Behavior, Pluggable Selector)
△ Anonymous Inner Class
△ Library Class
▽ Pluggable Block [Ruby]

状態

△ State
△ Access
● Direct Access (SBPP: Direct Variable Access)
● Indirect Access (SBPP: Indirect Variable Access)
● Common State
● Variable State
△ Extrinsic State
△ Variable
● Local Variable (SBPP: Temporary Variable)
 ●Collector/Count (SBPP: Collecting Temporary Variable)
 ●Explaining (SBPP: Explaining Temporary Variable)
 ●Reuse (SBPP: Reusing Temporary Variable)
 △Element
 ▽(SBPP: Caching Temporary Variable) [Ruby]
△ Field
△ Parameter
● Collecting Parameter
△ Optional Parameter
△ Var Args
△ Parameter Object
● Constant (SBPP: Constant Method)
● Role-Suggesting Name (SBPP: Role Suggesting Variable Name)
△ Declared Type
△ Initialization
● Eager Initialization (SBPP: Explicit Initialization)
● Lazy Initialization
△ Control Flow
△ Main Flow

メッセージ

● Message
● Choosing Message
● Double Dispatch
● Decomposing (Sequencing) Message (SBPP: Decomposing Message)
● Reversing Message (SBPP: Reversing Method)
△ Inviting Message
△ Explaining Message
△ Exceptional Flow
● Guard Clause
△ Exception
△ Checked Exceptions
△ Exception Propagation
▽ Dispatched Interpretation [Ruby]
▽ Mediating Protocol [Ruby]
▽ Super
▽ Extending Super
▽ Modifying Super

メソッド

● Composed Method
● Intention-Revealing Name (SBPP: Intention Revealing Selector)
△ Method Visibility
● Method Object
△ Overridden Method
△ Overloaded Method
△ Method Return Type
● Method Comment
● Helper Method (SBPP: Intention Revealing Message)
● Debug Print Method
● Conversion
● Conversion Method (SBPP: Converter Method)
● Conversion Constructor (SBPP: Converter Constructor Method)
● Creation (SBPP: Constructor Method)
● Complete Constructor (SBPP: Constructor Parameter Method)
● Factory Method (SBPP: Constructor Parameter Method)
△ Internal Factory
● Collection Access Method (SBPP: Collection Accessor Method)
● Boolean Setting Method (SBPP: Boolean Property Setting Method)
● Query Method
● Getting Method
● Setting Method
● Safe Copy (SBPP: Enumeration Method)
▽ Default Value Method [Ruby]
▽ Shortcut Constructor Method [Ruby]
▽ Comparing Method [Ruby (#<=>)]
▽ Execute Around Method [Ruby]

修正:

△Safe Copy → ● Safe Copy (SBPP: Enumeration Method)


コレクション

● Array
△ Iterable
● Collection
△ List
● Set
△ SortedSet
● Map (SBPP: Dictionary)
▽ OrderedCollection
▽ RunArray
▽ Equality Method [Ruby (#eql?)]
▽ Hashing Method [Ruby]
▽ SortedCollection
▽ ByteArray
▽ Interval [Ruby (Range)]
▽ IsEmpty [Ruby (#empty?)]
▽ Includes: [Ruby (#include)]
▽ Concatenation [Ruby (#+)]
▽ Enumeration [Ruby]
▽ Do [Ruby (#each)]
▽ Collect [Ruby]
▽ Select/Reject [Ruby]
▽ Detect [Ruby]
▽ Inject:into: [Ruby (#inject)]
▽ Duplicate Removing Set → [Ruby #uniq]
▽ Temporarily Sorted Collection → [Ruby #sort / #sort_by]
▽ Stack [Ruby (Array #push, #pop, #last, #size, #empty?)]
▽ Queue [Ruby (Array #unshift, #shift, #empty?, #size)]
▽ Searching Literal [Ruby] or → [Ruby (case-when)]
▽ Lookup Cache [Ruby (cache[key]||=val)]
▽ Parsing Stream
▽ Concatenation Stream → [Ruby #<<]

(SBPP: フォーマット)

▽ Inline Message Pattern
▽ Type Suggesting Parameter Name [Ruby]
▽ Indented Control Flow
▽ Rectangular Block
▽ Conditional Expresstion [Ruby]
▽ Simaple Enumeration Parameter
▽ Cascade
▽ Yourself
▽ Interesting Return Value [Ruby]