2015年7月1日水曜日

オブジェクト指向の間違いを正す

オブジェクト指向がしっくりこないと思ってたいたのがようやく構造設計でオブジェクト指向を設計したらようやく答えが見えたので書き留めておこうと思う。


私はIT業界に就業して、まず初めに構造設計から入り、1ソース数万行のソースコードに仕様追加などを経て、今まで対岸の存在であったオブジェクト指向だったはずが
「オブジェクト指向はいいよ」って布教活動する人が周りに増えてしまい、しぶしぶオブジェクト指向の世界に入信している。

しかしオブジェクト指向の世界はどうも無駄が多く、同じ名前の関数を複数のクラスにまたがって呼び合ったりする構造、ネストが深くなり逆に分かりにくいんじゃないの?ってさえ思った。

色んな本やネット、同僚からの話を聞いてもしっくりこない。

大規模なソースコードこそ悪とされる風習の中で1ソース数万行とかざらだった現場上がりの人間からすると、Grepだけで問題の個所に辿りつけたのに今じゃ小さなオブジェクトが無数にあって綱渡りして進まないと答えにたどり着けない。

その話をすると何を言ってるんだ、オブジェクト同士は互いに協調しあって動いているから回りに影響を与えない為にそうなっている。と説教されたとしても自分のイメージ空間には

「宇宙空間に漂う惑星が互いに協調しあっているんだ!」

と、目に見えないがそこにはあると言われても、オカルト的な宗教の勧誘を受けている感覚に襲われる。

自分の中にあるオブジェクト指向に対するモヤモヤとした感情はずっと片付かないものであったが、ようやく構造設計で学んだ知識を基にオブジェクト指向の概念を自分で構築してみてようやく答えが見つかったのだ。


何がしっくり来なかったのか説明する前に、まず生みの親も現在のオブジェクト指向は良いように見ていないのでそこから読みほどきたいと思う。

-------------------------------------------------------------
Eclipseを開発したDave Thomasや、オブジェクト指向という言葉の生みの親であるAlan Kay博士は、オブジェクト指向という言葉は失敗だったと語っている。
本来オブジェクト指向が重視すべきは「オブジェクト」ではなく「メッセージング」であるにもかかわらず「メッセージング」がおろそかにされているためである。特に言語の進歩において「オブジェクト」や「クラス」の側面ばかり強調される傾向にあり、Alan Kay博士は「Smalltalkが最高に好きという訳ではないが、他の言語に比べればマシである。」と述べている。

1つ目「オブジェクト指向という言葉は失敗」
 これはネット上や書籍の文献を読んでもわかる通り、漠然とした内容かつニュアンスがまちまち変わる。それはオブジェクト指向の多態性とも言える皮肉な事が挙げられると思っている。
つまり、

 アーキテクチャが正しく世に広まらなかったのでオブジェクト指向という言葉が失敗だった、と言える。

2つ目「重視すべきは「オブジェクト」ではなく「メッセージング」
 1つ目の言い分だろう。
 オブジェクト指向とは、から始まると必ず「カプセル化」、「多態性」、「再利用性」などがずらっと出てくる。この言葉を指すものが「クラス図」「オブジェクト図」となってしまう。誰がこれらをメリットだと言い放ったんだが知らないけど、きっとUMLの売り込み文句とオブジェクト指向を抱き合わせて普及させたからだと思う。


3つ目「特に言語の進歩において「オブジェクト」や「クラス」の側面ばかり強調される傾向」
 多重継承、インターフェイス、MixInなどなど、その辺りの事を指していて「理想のオブジェクト指向」とは別の進化を広がっているを受け取れる。

4つ目「Smalltalkが最高に好きという訳ではないが、他の言語に比べればマシである。」
 これを語るにはSmalltalkを学ばないと分からない。
ざっくり見てみると、
 オブジェクトビュアーなるものがあって、そこでオブジェクトを構築するそうだ。
 つまりオブジェクトがメイン。クラスは存在しない?


-------------------------------------------------------------


オブジェクト指向と向き合って、書籍を読んでからこれがオブジェクト指向だと学びしっくりこなくて
理解しようと色々やってみてようやく分かった事がある。

それはオブジェクト指向の書籍やネットを見るモデリング手法で描かれる

 オブジェクト図、クラス図の考えがごっちゃになっている。

よくある例は、汎化の説明で
 「飛行機」←{「ジェット機」「オスプレイ」「グライダー」}

をクラス図で表現しているが間違い。
この図はオブジェクト図で表現すべき項目である。

プログラム化すると

 インターフェイスを定義してインターフェイスを持つ実体クラスを定義する。

これは正しい。オブジェクト指向において基本的なやり方である。

が、違う点は1つある。

これはクラス図で表現するのではなく、オブジェクト図で表現すべき事象であるからだ。


 オブジェクトの表現はクラス図ではなく、オブジェクト図。

クラス図は
 「パソコン」←コンポジット―{CPU、メモリ、HDD、ヒートシンク}

といったように、

 クラスは箱であり、その中にオブジェクトを入れる。


ここでピンと理解できた人は意識の高い人だ。


分からなかったら基本的な事が基本的すぎて目の前にあるのに気付かない、そんな状態だろう。


・オブジェクトはオブジェクト(実体)

・クラスはクラス(箱)


というように意味が全く違う。

実体を表す為、プログラムの制約上

 クラス(設計図) → インスタンス生成 → オブジェクト(実体)


この流儀に沿ってプログラム化しないといけないので

オブジェクトを作るのみクラスを書く。これを利便性よくモデルクラスと呼ぶ。

モデルクラスには表現したいオブジェクトの要素を書き表す作業となるはずだ。


ここには振る舞いは存在しない、オブジェクトは置物みたいなものだから。


もしあなたが100円ショップに買物に来てフライパンを買ったとしよう。

そのフライパンは通常のフライパンとして扱う人もいれば、DIYで別の部品として使う人もいるだろう。

オブジェクトとはそんなものだ。

そのように理解してもらえれば振る舞いなんて後から使う人が決めればいいじゃんってなり、オブジェクト自体に振る舞いはいらない。

ここでプログラム要素を交えてまとめると、

モデルクラスのインスタンスから特定の振る舞いを行う(コントローラクラスの)オブジェクトを生成する。

これに尽きる。

最初に決めるのはモデルクラスであって振る舞いは後付でも構わない。


こうする事で

クラス図には動きのあるオブジェクトをどう組み合わせていくか


という視点で図が描かれていく。

もちろんオブジェクトを表現するモデルクラスも出てくる。

出てくるものは汎化した最上位クラスが登場する。インターフェイスではない。


文頭で書いたようにクラス図もオブジェクト図もごっちゃになってクラス設計をすると

出来上がるソフトもごっちゃになって、無用なネストが多発しやすくなる。

さらに新しいモデルを作る時に回りに与える影響が大きくなってしまう。

つまり、本当に理解した人以外はオブジェクト指向を語ると混乱の元になって

汎化・特化・集約などを意識してやってみたがどうもうまくいかない。

なぜなら似たオブジェクトなのに別クラスで定義されているからなんて事が発生する。

こういう事が言いたかった。


長くなったので、今回はクラス図とオブジェクト図についての説明で終えようと思う。

コメントを投稿

Androider