※コメントが大変モチベになりました。ありがとうございます。まだまだコメント待ってます。
※前半は読み物みたいなもので、後半が本題です。後半だけ読んでも構いません。
稀に来て妙なことを書き込む癖が治りませんね。SUEです。(アカウント作り直しましたが、前垢に特別想い入れはないので心配無用です)
さて今回の用事は、オブジェクト指向の問題とその改善案についてです。
オブジェクト指向への批判なぞ既出も既出ですが、どれも的を射ていない感がありました。
というわけで、僕なりに問題の本質とその解決法まで考えたので、ぜひフィードバックください。
結構頑張って書いてしまいました。斜め読みでも構わないので読んでいただきたいです。
一つはじめに注目したのは、例外処理についてでした。
オブジェクト間の例外処理は、大きな矛盾を孕んでいると思います。
例外の発想とは、仕事を投げる処理は簡潔にして、どうしてものとき例外で受ける、というものだと思います。
しかし、例外は結局受ける処理を書かなければ死あるのみです。
受ける処理を書くなら書くで、非常に面倒な例外機構が待っています。
それなら最初から、例外機構をなくし、仕事の投げ方に例外対応を含めるのが一番楽なのでは?
goなどは複数返り値で例外相当のものを表せるわけで、そのほうが苦労しなくていいと思いますね。
いまどき言語Swiftにも例外はないそうですし。
思うに、オブジェクト指向のメッセージング全体に同じ発想があるのではないでしょうか。
仕事は一方的に投げて済ます。という発想です。
実際には、エラー対応など、双方向で扱うと楽なことは案外多いです。
これがオブジェクト指向の第一の問題です。
もし現実であれば、一方的に仕事を押し付けていることになりますからね。
押し付けよりは、互いに必要なデータと起こりうる事態を想定して、話し合いの手順を取り決める。
実際に仕事を投げるときは、話し合ってから仕事を投げる。
というようになるでしょう。
もう一つ行き当たったのが、オブジェクト指向の経歴でした。
オブジェクト指向は、Smalltalkから始まりました。
そのSmalltalkの最も重視していたのは、実はオブジェクトではなくオブジェクト間の通信でした。
今のほとんどのオブジェクト指向言語では、そこんところが曖昧になっているような気がします。
普通にプログラミングをしていても、オブジェクトをどう切り分けるかより、オブジェクト間でどう連携するかに苦労すると思います。これ、僕だけじゃないですよね?
オブジェクト「そのもの」よりも、オブジェクトの「関係」に注目して書く方法が欲しいです。
これがオブジェクト指向第二の問題です。
最後に見たのは関数型との比較でした。大体関数型~言語がいかに優れているかという内容でしたが。
確かに優れていると言えばその通りです。それはなぜか。非常にコンピュータのやり方と一致しているからです。
コンピュータのやり方とは、小さなものを組み合わせて大きい処理をするボトムアップ型のやり方です。
しかし一方、人間のやり方は、大きな概念から徐々に細かくしていくトップダウン型…が多め、というか、より自然です。
ここで、関数型言語の難しさが現れてきます。
オブジェクト指向はその点、トップダウン型に近いものではありますが、上記の問題もあって必ずしも自然ではありません。
ここからが本題
批判するのはここまでです。
もっと大事なのは、これらをどう解決するかということです。
その答えはズバリ「役割」と「実体」です。
「役割」がインターフェイス、「実体」がクラスと考えてほぼ間違いありません。
ん? じゃあやることは普通のオブジェクト指向と同じ? と思われた方、鋭い。
インターフェイスとクラス、どちらもよくある機能ですが、使い方と考え方を変える必要があります。
たとえば、「上司」という役割を詳しく見てみましょう。
●「上司」は「部下たち」をメンバに持ちます。「部下たち」との間では、「上司」と「部下」という役割に定義された方法でやりとりをします。
●「上司」も「部下たち」も、実際に田中さんが入るか鈴木さんが入るかは問題ではありません。
肝なのは、ここで普通「上司」クラスの「吉田さん」インスタンスとするところをぐっと堪えて、
「上司」インターフェイスを持つ「吉田さん」クラスの「吉田さん」インスタンスを作ること
です。
なんでこんな面倒なことになってしまったをするのか? 答えは次の例を考えれば分かります。
吉田さんは、会社では「上司」ですが、家に帰れば「父親」であるとしましょう。この場合の実装は、
「上司」と「父親」インターフェイスを持つ「吉田さん」クラスの「吉田さん」インスタンス
になります。
見えてきましたか? そう、役割は複数あるものなのです。ここ重要。
よくあるオブジェクト指向の階層化が上手く書けない原因は、このように一つの実体に複数の階層(「会社」と「家庭」)が絡むことがあるからです。
なお、この吉田さんのように同時に両立できない役割の場合、上手く(勤務時間か否かなど)で役割を切り替える必要があります。
とりあえずゲームプログラミングにおいて両立できないことは少ないと思いますが、
この吉田さんは仕事と家庭どっちが大事なのか判別できなくなったら、assertを吐いて実行を停止するしかないですね。
オフトピック
吉田さんはメンバに手足インターフェイスを持ち、手足インターフェイスは細胞インターフェイスと…とやるとキリがないです。
メンバをインターフェイス扱いするのはいい感じのところで止めましょう。
メンバをインターフェイス扱いするのはいい感じのところで止めましょう。
なんか面倒だなあと思われるかもしれません。しかしこうするメリットは非常に大きいです。
まず、外のオブジェクトとやりとりするには必ず役割に定義された方法を使う必要があります。
言い換えれば、オブジェクト同士の関係は全て役割に書いてあるということです。
これにより、役割分担が極めて自然に行えます。プログラマである必要すらありません。
実体の細かい処理を書くのはプログラマの仕事です。
でも実体は自分自身のことと、果たすべき役割に専念していればOKです。
実体の方も、現実の実体とよく対応してくれるので分かりやすくなります。
だいぶ長く書きました。分かってくれるかな……
分かってしまえば後は、吉田さんに似て非なるクローンオブジェクトを作るも、クラスの捉え方を変えるも自由です。
ひと通り書きたいことは書きました。改めて意見を下さった方々に感謝します。
おかしな点や不思議な点はどんどん質問してください、命の限り返信します。
► スポイラーを表示