先日、こんな記事がありました。[初心者]オブジェクト指向でなぜつくるのか
本の要約だそうで、私は対象の本を読んでないので記事が正しいかはよくわかりません。
ですが、一つ気になる記述がありました。
現実世界では、赤ちゃんは大人になり、老人になる。しかしオブジェクト指向の世界では、作られたインスタンスは複数のクラスに帰属することができず、時間が経っても別のクラスに所属替えできない。
これはおそらくクラス図にするとこういうことでしょう。もし間違っていたら連絡していただければ修正します。
赤ちゃんは人間であり、大人も人間である。よって赤ちゃんと大人は人間のサブクラスであり、
現実世界の赤ちゃんは大人になるので同じオブジェクトが別のサブクラスのインスタンスへ変位すると。
これは一見正しいように見えますがよくある間違いです。
クラスはただの分類ではありません。オブジェクトを抽象化したものであり、invariant を記述したものです。一方成長段階は多値を取りえる(variant)概念です。variant なクラスなどというものは存在しません。…これだけでは何を言ってるかわからないですよね。
こういえばわかりやすいでしょうか?
仮に、赤ちゃんと大人を人間のサブクラスとして赤ちゃんは成長して人間になれるとする。では、モヒカンとツインテールも人のサブクラスとした場合にモヒカンは成長したらツインテールになれるか?モヒカンは大人になれないのか?なれないとしたら、赤ちゃん&大人の関係とモヒカン&ツインテールの関係を区別することはできるか?
ということです。
と言ってもやっぱりわかりにくいですよね。
結論として正しいクラス図はこうなります。
この「年代」は「属性」であり、時間によって変わるため「状態」です。簡略化して属性スロットに入れてしまってもいいでしょう。念のため言っておきますがこの「属性」だの「状態」だのというのは別にメモリ上のデータでもなければプログラミング上の概念でもありません。ある人は赤ん坊の状態のこともあれば大人の状態のこともあるだろうというただそれだけの話です。
「元の人間クラス」の悪い例として、同じように例えば私が今「モヒカンの人」だったとして、成長して「ツインテールの人」になったとしましょう。
さて、この考え方は正しいでしょうか?
一方、例えば私が今「モヒカンの髪型」だったとして、成長して「ツインテールの髪型」になったとしましょう。
人間としてはマージされましたが、年代と髪型は混ざっていませんね。
さて、先ほどのクラス図との違いは何でしょうか?
言うまでもないですね。混ぜてはいけないものを区別して扱えている、ということです。
このように、人が赤ちゃんだったり大人だったりすること・モヒカンだったりツインテールだったりすることは可変 variant です。
一方、赤ちゃんであることとモヒカンであることは別々の事柄であり、別々の事柄であることは決して変わりません。この決して変わらない構造、存在に対する限定こそが invariant であり、クラスで記述するべきことです。
クラスのもとになったイデアとか形相とかは「その文脈の中で変更されないこと」を記述するための手法であり、我々は今何の話をしているのかを規定するものです。
あるクラスのインスタンスが別のクラスのインスタンスにもなれるとした場合、「我々は今何の話をしているのか」のすべてが崩壊します。
これは現実だとかプログラムだとかに限らず「あなたは対象を正しくモデル化できるか。そのモデルを記述するときに論理的に正しく記述できるか」という問題です。
最近、早すぎる抽象化だとか間違った抽象化だとかの記事に多くの良いねが集まっていますが、プログラミング以前に対象としている物事をモデル化することに失敗しているのではないでしょうか?
よくプログラミングのモデル化は難しいとか現実とプログラミングは違うと言う人がいますが、そう言う人が現実をうまくモデル化できている例を見たことがありません。現実のモデル化ができないのなら現実とプログラミングの違いもへったくれもありませんし、早かろうが遅かろうが抽象化はうまくいかないんじゃないですかね。
抽象化の仕方を教える先生とか教科書とか見たことないので難しいところですが勉強とか練習とかしていきたいところです。
まあ現実のモデリングはプログラミング上のモデリングより難しかったりするんですけどねHAHAHA!