オブジェクト指向超入門〜第6回〜
オブジェクト指向のポリシーでもうひとつ重要な点は、保持しているデータは常に矛盾や破綻がないという事です。どっかのバカがムチャクチャな使い方をしても、決して13月42日のような日付になってしまってはいけません。それは使う側ではなくクラス自身に、そのような事態になってしまう可能性を排除する責任があるのでした。
その為に変数をprivateにし、アクセスメソッドでは渡された引数の値を適切にチェックして、変数同士が矛盾しないように処理する必要があります。そのようにして考えられる穴を出来る限り塞いでおくほど「堅牢な」クラスになります。クラスが堅牢になるほどシステムのバグは少なくなり、またバグが起こってもその原因が特定の箇所に限定され修正しやすくなります。
ではクラスのメソッドをこのようにしっかり作っておいて破綻の可能性を排除すれば、オブジェクトが予期しない状態になるのを100%防げるでしょうか。どんなにメソッドを頑丈に作っても、オブジェクトの状態が不定になる可能性がひとつだけ残っています。それはオブジェクトをnewした直後です。
MyDate today = new MyDate();
today.addDay(10); // どうなる?
オブジェクトを生成した直後には正しい日付は保持されていません。このクラスではnewした後に setYy(2008); setMm(12); などを呼んでもらう事を想定しています。これは言ってみれば使用者に使い方を強制している事になります。しかしオブジェクト指向では「どこでどんな無茶な使い方をされるかわかったもんじゃない」「使用者は分別を持ってくれるはず、なんてのはハナから信用しない」という思想が根底にあります。だからオブジェクトが矛盾した状態にならないようにするのはクラス自身の責任なのでした。であればnewした直後でさえも破綻の可能性を排除するのはやはりクラスの責任です。コンストラクタはその為に導入された文法です。
pulic MyDate() {
// 2000年1月1日を初期値とする
yy = 2000;
mm = 1;
dd = 1;
}
普通は本日の日付を取得してきて初期値とする、などが実用的な実装なのでしょうが、とにかく「変な」日付が保持される可能性はこれで完全に排除できる訳です。コンストラクタはこのようなオブジェクト指向のポリシーを貫くための文法です。太古の昔から言われている「変数は宣言したらまず初期化しよう」という初心者用の教科書に書いてあるようなくだらない仕事をするために導入されたのではありません。
わかってない人はコンストラクタで単純な初期化しかしない場合が見受けられます。この場合、型がintだからという単純な理由で変数にゼロを代入するといった具合です。0年0月0日という日付オブジェクトが出来上がるようではコンストラクタの役割を果たしていません。
>オブジェクトの状態が不定になる可能性がひとつだけ残っています。
「一つだけ」と言われていますが、実装によりますが、残念ながら他にもオブジェクトの状態が不定になる可能性が少なくとも1つあります。もう少し正確に説明すると状態が不定にならないようにすると面倒な問題が出てきます。
オブジェクト指向プログラミングの難しいところの1つは、こういった理想(カプセル化)と現実(日付クラスの実現)のギャップにあります。カプセル化をきちんと行うにしても現実には漏れが発生し簡単な例でも開発が面倒になるところです。
上記の点についてコメント頂ければと思います。