言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

Designing Reusable Classes

http://www.laputan.org/drc/drc.html

新年早々風邪をひいてしまったのでずっと家で読み物をしていた。ちょっと古いが 1998 年に書かれた Ralph E. Johnson と Brian Foote の Designing Reusable Classes のメモ。内容はフレームワーク(ライブラリ集)の設計の仕方。

ホワイトボックス対ブラックボックス

昔風のライブラリでは、具体的な機能を実装するためにサブクラスで特定のメソッドを実装させるという事が良くある。これがホワイトボックス。例えば onmouseup でマウスアップ時の動作を記述する等。この欠点は、継承機構を利用するため、フレームワークとユーザコードのカプセル化が保証出来ない事。例えばうっかり知らずにメソッドをオーバーライドしたり、触ってはいけない内部状態を変更出来てしまう。

これに対してブラックボックスでは、継承機構を使わずに実装を与える。イベントハンドラや、Smalltalk にある pluggable ビュー等。

フレームワーク設計 13 のコツ

1 再帰的なメソッド

同じような動作には同じメソッド名を付けて再帰的に動くようにする。Composite パターンと同じ。

2 場合分けを無くす

クラスに応じて if で場合分けをしているコードはほとんど間違い。メソッドディスパッチを利用するべき。

3 引数を減らす

コンストラクタ以外でたくさん引数があるのは間違い。

4 メソッドを小さくする

長いメソッドは間違い。小さなたくさんのメソッドに分割するべき。

5 クラス階層は深く狭く

一つのクラスにたくさんのサブクラスがあるのは間違い。共通項をくくりだして新たなスーパークラスを作るべき。

6 クラス階層の一番上は抽象クラス

スーパークラスに状態を持たせるとサブクラスで実装を変えられないので、一番上は抽象クラスで無ければならない。

7 インスタンス変数へのアクセスは少なめに

アクセッサーを定義して実装依存を減らそう。

8 サブクラスは特殊化

サブクラスはスーパークラスのメソッドを再定義してはならない(抽象メソッドは除く)。

9 大きなクラスは分割する

大きなクラスは貧弱な設計の証拠だ。

10 実装の違いを整理して別のコンポーネントに分ける

一つのメソッドを、あるサブクラスがある方法で実装し、他のサブクラスが別の方法で実装している時はクラスの分け方に問題がある(この部分良くわからなかった)。

11 関係無いメソッドを分ける

クラスの一部のメソッドが他の一部のメソッドをほとんど利用しない時は、クラスを分けて委譲を使う。

12 self の代わりにコンポーネントにメッセージを送る

self を使ってサブクラスのメソッドを呼ぶようなフレームワークは、ブラックボックス化して代わりに委譲でメッセージを呼ぶように作り替える。

13 暗黙のパラメータを無くす

インスタンス変数を暗黙のパラメータとして使わない。グローバル変数と同じようにコードの維持が難しくなる。

感想

ここに書いてある事は他でも良く聞く話だけど、一つ同意出来ないのが 5 番のクラス階層は深く狭くという点。他の部分では継承を出来るだけ使わない方向に見えるので矛盾を感じた。この頃はまだ継承がかっこ良かったのか。ふと思ったんだけど、プログラミング実装技術について、歴史的な文書を順にみてゆくと先のトレンドが読めるかも知れない。

ここで継承がどれだけ悪いか、特に状態を伴った継承を撲滅するために私達に何が出来るかという点について書こうと思ったけど関係ない話になるのでやめておく。