| 著作一覧 |
はるか昔、子供がまだ子供にも成りきらないころのことだ。
ディズニーのダンボかバンビか、そのあたりのLDを見せていたら、広告のピーターパンにやたら興味を持って、買ってくれと言いだした。
まあ、いいかな。で、ピーターパンのLDを買ってやった。
ピーターパン 【日本語吹き替え版】 [DVD] ANC-008(ハミルトン・ラスケ)
で、それから毎日、子供はピーターパンを見るようになった。
だが、そんなに毎日欠かさず見るほどおもしろいか?
でも、とにかく、何か見ると言えばピーターパンだ。
一緒に見ているこっちがすべてのセリフを覚え、フック船長とピーターとスミーのトリオ芸をぬいぐるみで見せられるまでになったころ、画面を眺めながら子供がぽつりと言った。
「いつ、迎えに来るんでしょうね」
?
そして、話を聞き、ダンボだかバンビだかのLDを見直し、ピーターパンの広告で、ナレーションが「ピーターがあなたを夢の世界へご招待します」とか入るのを確認した。思わず、抱っこしてやったのは言うまでもない。
というエピソードを女の子の宇宙冒険を読んでいて脈絡もなく、思い出した。
たったひとつの冴えたやりかた 改訳版(ジェイムズ・ティプトリー・ジュニア)
(でもおれは文庫版のほうを買った。ただ、つうかではなくっていうかにしたいな。っていうか、おれは最後にエイリアンの名前を「静かな声」で付け加えたのは親父だと思うがそこは技術的になんとも言えない嫌な感じを受けたが、しょうがあるまい)
島田さんからもらったプロダクティブ・プログラマを読んでいたら、実にわかりやすいデメテル則の説明が出ていたので感心した。
プロダクティブ・プログラマ -プログラマのための生産性向上術 (THEORY/IN/PRACTICE)(Neal Ford)
「メソッド呼び出しに"."を2つ以上使うな」
これこそ情報隠蔽とは具体的にどういうことかということを示すものだ(注:多分、著者のオリジナルな意見というわけではない。どこかで見た覚えはある)。
一般に、次のAPIはあまり良くないとされている。
public ArrayList<String> getNames();
代わりに次を利用しろ、と言われる(し、多くの場合でおれも言う)。
public List<String> getNames();
これはなぜかというと、このメソッドの実装の自由度を上げたいからだ。とは言うものの、よほどの要素数を持たない限り、今ではArrayList以外を利用する意味はないような気はするが、それは別の話だ。
そしてご存じなんでもprivateフィールド主義者がくる。
彼らは、privateとフィールドにつけることが情報隠蔽であり、つまりカプセル化だと無邪気に信じる。
public class Foo {
public List<String> getNames() {
...
}
}
彼らはFooのインスタンスを内包するクラスBarを次のように実装する。
public class Bar {
private Foo foo;
public Foo getFoo() {
assert foo != null;
reutrn foo;
}
}
でも、これは全然、情報を隠蔽していない。
なぜか? Barクラスを利用してみよう。
Bar bar = new Bar();
Foo foo = bar.getFoo(); // 強調のために分割したが、次行と合わせて"."2個以上ということだ。
for (String name : foo.getNames()) {
...
}
えーと、これって、BarがFooに依存しているという事実を全世界にpublicにしているからこう書かざるを得ないということですね。つまり、Barの現時点の実装ではFooを利用して名前を格納しているという実装詳細に関する情報がまったく隠蔽されていないということだ。
そうではなく、Barは何かの理由でいろいろな名前のコレクションを提供したくて、そのためにFooを内包しているはずだ。もし、Fooではないものを使いたくなったら、いつだって乗り換えられるようにしておくのが正しい設計というものだ。これはArrayList<String>ではなく、List<String>を返すメソッドのほうがよいというのと同じ話だ。
であれば、public Foo getFoo(); などというAPIが出てくるわけがない。
package com.example.foobar.blabla;
public Bar {
Foo foo; // blablaの仲間は使って良い
public List<String> getNames() {
return foo.getNames();
}
}
こうでなくては。
そしてある春の日、Fooがバギーで全然だめなことがわかる。Barは名前コレクションの自前実装が求められる。
public Bar {
ArrayList<String> names;
public List<String> getNames() {
return new ArrayList<String>(names); // read-only の場合
}
}
Fooを返すようにAPIを切っていたら、もちろん、こういうことはできない。
public Bar {
ArrayList<String> names;
public Foo getFoo() {
Foo foo = new Foo();
// リフレクションを駆使してfooをクラックして解析した結果から求めたインスタンス変数にnamesのコピーを設定する
return foo;
}
}
まあ、やればできるけど、全然プロダクティブじゃないね。
それとは別に、ここでコンテキストを考える、ということも考えなければだめだ。
値オブジェクトの値オブジェクトというようなものが、必要となることがあるからだ。別に値オブジェクトではなくとも構わないけど。
public class Hoi {
public String getA() { ... }
public String getB() { ... }
...
値オブジェクトHoiを内包するクラスChoiを考えてみる。
コンテキストを無視して、上に書いたデメテル信者は次のように実装する。
public class Choi {
public String getA() { return hoi.getA(); }
...
public String getAA() { return fieldAA; }
...
}
そして、Choiを内包するProクラスを次のように実装する。
public class Pro {
public String getA() { return choi.getA(); }
...
public String getAA() { return choi.getAA(); }
...
public String getAAA() { return fieldAAA; }
...
}
だから信者ってのはだめなんだよ。
でも、彼らの信念は固い。たったひとつの冴えない規約(内包したオブジェクトを直接返すの禁止!)を闇雲に信心すれば、実装時に何も判断しなくて済むから、高効率的だと信じ込んでいるからだ。でも、全然、効率的にはぱっとしないと、上のChoiだのProだのを眺めれば思うのだが。
「いえ、Eclipseを使えば簡単に実装できます」
まさしく、プロダクティブだな。4種の兵隊のうち、勤勉でしかも……ということか。
ジェズイットを見習え |
>4種の兵隊のうち、勤勉でしかも……<br>これは孫子でしたっけ?<br><br>リファクタリングウェットウェアといい、書評がおもしろいです。<br>書評を読むとその本、読みたくなります。
こんにちは。<br>なんか諸説あるようですが、ゼークトのつもりです。孫子のは、敵の中にはこちらの上、敵の下にはこちらの中、敵の上にはこちらの下をぶつけよ、というようなのだったような。
こんにちは。どうもありがとうございます。<br><br>孫子のは「無謀・慎重」「有能・無能」だったと思ったんですが(無能で無謀なら特攻させろ、有能で慎重なら守らせろ、のような感じで)、勘違いしてたみたいです。<br>。
デメテルと聞いて! 「他で読んだかも」は『ThoughtWorksアンソロジー』のオブジェクト指向エクササイズですかね……これの元ネタの記事の翻訳をどなたかがしていたような気がするのですがそれを忘れてしまいました。
soさん、孫子にもあるんですね。ドイツ周辺では中国ブームがあったはずなので、それが元ネタかも知れませんよ。