ひがやすを技術ブログ

電通国際情報サービスのプログラマ

レガシーなオブジェクト指向


データと振る舞いを1つにカプセル化する。
これは、オブジェクト指向の重要なポイントです。クラスの持つ最も重要な性質だといえるでしょう。
しかし、なんでもかんでもデータと振る舞いを一緒にすれば良いということもありません。
クラス設計の重要な原則である単一責任の原則に違反してしまう可能性があります。
この部分が最もオブジェクト指向で誤解されているのではないでしょうか。
クラスが1つの役割だけを担うのなら、振る舞いも役割に応じてそれぞれのクラスに割り当てられるべきだと思います。
私自身も何度も間違いを犯してきました。
例えば、S2DaoでBeanのメタ情報を格納しているBeanMetaDataというクラス(インターフェース)があります。SQLを自動生成したり、Beanからバインド変数を組み立てたりという仕事は、これまで、BeanMetaDataにさせてました。データのことを最も知ってるクラスに振る舞いを持たせるのは、自然なことだと思っていたためです。
しかし、S2Daoに仕様の追加があるたびに、BeanMetaDataに変更が入るのです。メタ情報は全く変更されていないのにもかかわらず。
これは、BeanMetaDataに多くの責任を持たせていたためです。SQLを自動生成したり、Beanからバインド変数を組み立てたりという役割は、メタデータを管理するというBeanMetaDataの本来の役割とは異なることなので、別なクラスに任せるべきだったのです。
振る舞いを役割ごとに分割する、言い方を変えると振る舞いをモデリングするという考えは、重要ながらかなり見落とされていることが多いのではないでしょうか。
単にデータと振る舞いを一緒にするというのは、レガシーなオブジェクト指向であり、そこに振る舞いのモデリングの観点を追加すべきだと思います。

Fatなクラスよ、さようなら

役割ごとにクラスを分割するという観点で考えると、

  • 永続化されるデータを管理するクラス
  • データベースにアクセスするクラス
  • 業務ロジックを扱うクラス

に別れるというのは、理にかなったことだということが分かると思います。
業務ロジックを扱うクラスは、役割に応じて分割されます。この役割による分割は、多くの場合、業務機能(海面レベルのユースケース)ごとに行うのが良いのではないかと思います。
さらに、複数の業務機能で共通的に使われる機能は、補助ロジッククラスとして役割ごとに分割されるわけです。
永続化されるデータに業務に応じた振る舞いを持たせるというのは、1つのクラスに複数の役割を持たせることになります。データと振る舞いを一緒にするという観点から見ると一見正解に見えますが、クラスが複数の役割を担っているので、良くないクラス設計な訳です。

レガシーなオブジェクト指向よ、さようなら