OOとはなにか

自分の中でひっかがりを感じることを整理するため、なんとなく、こんな図を書いてみて、それからそれに文章を付けてみます。

マルが OOPやOOの名前、四角がそれを構成する要素・・・みたいな感じの適当な図です。また、赤の四角がプログラムの構造についての考え方、青の四角が型チェックについての考え方。用語や関係は適当です。(ご容赦)

クラスには「型」と「モジュール」の、二つのとらえ方があります。メイヤー先生の「オブジェクト指向入門」から(artonさんをパクって)引用すると、

繰り返しになるが、クラスを型と見るか、またはモジュールと見るかによってすべては決まる。型として見る場合、継承はis-a(……は……の一種である)という関係であり、明らかに特殊化である。"犬"は"動物"よりも特殊な概念であり、"長方形"は"多角形"よりも特殊化されている。この関係はすでに述べた部分集合の関係に対応する。(中略)

一方、モジュールという点から見ると、クラスはサービスの提供者としてとらえることができる。BはAのサービス(特性:feature)に独自の特性を追加したサービスを提供する。したがって、実現される特性という点で考えると、この関係は逆の部分集合となる。Aのインスタンスに適用される特性はBのインスタンスに適用され得る特性の部分集合である。

ということです。


* * *


抽象データ型のOOP はとにかく「(継承機能付きの)抽象データ型を『クラス』と呼ぶこと」自体がそのパワーでありアイデンティティでした。それこそ肝だったのです。

なので、集合論のような考え方――ドメインを分析し分類したモノをプログラムの構造とする、というのは普通でした。そのように分類すれば自然と型もついてくる、という考え方なのかな?古典的(=デザインパターン以前の)C++オンリーなOO本では、この二つを分けて考えていない・・・自然と同時に満たすという風潮がたしかにあったように感じます。そこで良く取り上げられる例が、「動物」を派生した「犬」と「猫」がいて、「鳴け」といえばワンニャー!な例。

でもそれは「型」を考えるときだけOKな考え方で、プログラム構造(モジュール分け)を考えるときには悪い方法です。

「プログラムにどのような構造を持たせるか」を、概念の抽象階層に分類に依らせると たいてい上手くいきません。それは「そのモジュールはどのような構造を持っているか」と「そのモジュールをどのように扱いたいか」は切り離して考えるべきで、かつ後者は「誰が」によって分類が容易に変わるものだからです。「ほ乳類」という共通項を見いだしたいときと、「泳ぐ生き物」という共通項を見いだしたいとき、それぞれ毎に「イルカ」の同じ分類仲間は変わるでしょ?でも「イルカ」の構造はいつだって変わりません。そういうジレンマに道を迷えば、

3.1 多重分類と動的分類
実は現在主流となっているオブジェクト指向プログラミング言語にはある制約があります。それは「オブジェクトが帰属するクラスは唯一で、かつ帰属するクラスを変更することができない」というものです。あまり一般的な用語ではありませんが、前者を単一分類 (single classification) 、後者を静的分類 (static classification) と呼びます。
つまり会社員、学生をクラスとして定義した場合には、ある人が会社員になったり、学生になったりすることをオブジェクト指向プログラミング言語では直接表現できないのです。

オブジェクト指向は本当に「オブジェクト」指向か?

のように、迷宮の奥底まで連れて行かれてしまいます*1


* * *


モジュールについて継承を考えるときは、継承は共通の処理をベースクラスに括り出す、差分プログラミングの手段と考えるべきです。この場合継承は拡張です。型について考えるとき、継承は特化ですが、これは複数のオブジェクトを同じ物のように扱いたいとき、即ち呼び出し元の共通化ポリモーフィズムのための物です。それらは区別して考えるべきで、また、プログラムの構造化は 開放閉鎖原則に沿うようにするのが上手い方法です。

これらの帰結から、抽象データ型のOOPも、プログラムにもたらすべき構造を 当初の「クラス分け主義」から「責務分散協調系」にシフトすることになりました。(それまで良いモノとされていたプログラムの構造が 一転して悪いモノになりました。価値観の転換はまさにパラダイムシフト?)


この「責務分散協調系の構造をプログラムにもたらす」は、メッセージングのOOPの流派でした。最初から生物の組織と細胞を プログラムの構造のメタファとし、さらに細胞間のやりとりを「メッセージ」と喩えたのですから、人として軸がブレてないわけです。

が、抽象データ型のOOP でもメイヤー先生の本を見れば判るとおり、勝手に(というか既に)そうなっていたはずで、GoFデザインパターンが、抽象データ型のOOP のコアたる価値観をごっそり変えた・・・という訳ではなさそうです(独自の進化が集約した?)。が、地道にジワジワではなく、一気にパラダイムシフトを迫った「デザインパターン来訪」というイベントは、そういう意味のある物だと思います。


現在において、OO とは「デザインパターンOOP」――オブジェクトを使い、責務分散協調系の構造をプログラムにもたらすプログラミング手法と言って良いと思います。

ワンニャーOOP」(と、ついでに「メッセージメタファ」は)既に、OOのエッセンス(「それがOO」というもの)では無くなりました。プログラムにもたらす構造の「べき」論として、抽象データ型のOOP も メッセージングのOOP も、今は大差はないとわたしは考えています。

一方で、抽象データ型のOOP と メッセージングのOOP の二つの派閥で、未だに OO のエッセンスとして位置づけが異なるのが「型」についての考え方だと思います。前者は 型継承によるポリモーフィズムの実現も OO のエッセンスで、だから 総称は OOP じゃない新しいプログラミングパラダイムだ、と捉えたり。せっかく「一つのOO」になったと思ったのですが、そう上手くいきませんね。やっぱり「二つのOO」を意識しないと、本を読んだり勉強したりに混乱するのです。

とほほ。

大切なことなので2回リンクしました。

*1:オブジェクト指向でなぜつくるのか」の筆者の平澤さんの迷宮時代(?)の文章。平澤さんは後に同書のなかで「現実世界との対比はたとえ話として割り切るのがコツ」と当時の失敗を振り返って言っています。