オブジェクト指向超入門〜第5回〜

これまでの構造体に対して関数をメンバとする事ができるとなると、日付共通ライブラリなるものに用意されていた関数は全てクラスのメンバになります。ある日付の10日後の日付を求める為の共通関数の呼び出し addDay(today, 10); は today.addDay(10); となります。
これは見た目にはコードの表記法がちょっと変わった程度の違いでしかありませんが、実は非常に大きな考え方の変化があります。これまでの発想では日付に日数を足すという処理がまずあって、そいつに足される日付と足す日数の2つのデータを渡してやり、処理結果として10日後の日付というデータを受け取る、というように処理に従属する形でデータが現れます。

オブジェクト指向ではこの処理とデータの関係が180度逆転します。まず日付というデータ(=オブジェクト)がありきで、処理はそれを行うべきデータ自身にやらせるという発想になります。today.addDay(10); という記述は「todayさん、あなたに10日足してください。」と日付オブジェクトに対してお願いしているという意味になります。日付に10日足すという仕事は誰がやるべきかというとそれは日付自身であって、自分のことは自分で責任を持ってやる(=他人が面倒を見る筋合いは無い)という考え方です。

『データ自身に仕事をさせる』あるいは『自分のことは自分で責任を持つ』という考え方はオブジェクト指向への大きなパラダイムシフトです。処理とデータの主従関係が逆転するというのは、天と地がひっくり返るほどの非常に大きなポリシーの変化であり、この点を理解しないとオブジェクト指向の本質は理解できません。オブジェクト指向をわかっていない人はこの部分がわかっていないのです。

わかっていない人がクラス設計をやると「日付ユーティリティクラス」なるものがあって、そのメンバに addDay(MyDate date, int days) という関数を作っている例を実際の現場でよく目にします。構造体と共通ライブラリの発想そのまんまでオブジェクト指向はまるで無視です。こういう共通関数を作る為には MyDate のメンバ変数は全て丸見えになっていないと実現不可能な訳ですが、全ての変数に対して単純なgetterとsetterが用意されているだけだったりします。

class MyDate {
  private int dd;
  public getDd() {
    return dd;
  }
  public setDd(int dd) {
    this.dd = dd;
  }
}

わかってない人がやらかす典型的な例で『変数はprivateで定義しましょう』『変数をアクセスする為のgetterとsetterを変数とペアで用意しましょう』と何も考えずに条件反射的にコーディングしてしまっています。変数をprivateにする理由を今一度思い出してみましょう。getterとsetterを常にコーディングするのと変数をpublicで宣言するのとで何か違いがあるのか考えてみましょう。
このようなコードでは構造体での問題点はひとつも解決しません。