デザインパターンとともに学ぶオブジェクト指向のこころ を読んだ

読んだ理由

最近、ソフトウェアの設計力が不足していると感じる。もっといい感じにクラスを設計して、オブジェクト指向ぽいプログラムを書けるようになりたい。しかもスピード感を持ってやりたい。ということで、いまさらだけど、オブジェクト指向についてもう一度学んでみようと思った。本を読めばいいという訳じゃないけど、とりあえずもっと知識を増やしたい。渋谷の東急百貨店 7F の丸善ジュンク堂書店に行って、

の3冊で悩んだ結果、これを買った。決める要因となったのは、

というあたり。

オブジェクト指向について解説した章」としては、例えば以下のような章がある。

この本に書いてあること

以下のことが印象に残った。

オブジェクト指向パラダイムでは、問題を3つの観点から捉えなければならない

3つの観点とは以下のこと。

  • 概念(conceptual)
    • 私は何に対して責任があるのか?
  • 仕様(specification)
    • 私はどのように使用されるか?
  • 実装(implementation)
    • 私はどのように自身の責任を全うするのか?

オブジェクトは、あるレベル(概念)でコミュニケーションを図り、他のレベル(実装)でそれを遂行するとのこと。例えばポリモーフィズムは、

  • オブジェクトに概念的な作業を指示すると、実装に応じて、異なった動作が行われる

ということになる。

デザインパターンを導き出す

この本には、具体的な問題を例に Bridge パターンを導き出すという章がある。

オブジェクト指向設計の基本原則を適用し、Bridge パターンに向けた解決策を導き出していきましょう。この作業には、Jim Coplien の共通性/可変性分析を使用します。

この説明がとてもよかった。 これまでデザインパターンというと、なにかカタログ的な説明しか読んだことがなかったので、ある問題を解決するための設計プロセスを通してパターンが導き出されるというのは興味深かった。

共通性/可変性分析

この本では、よくある名詞と動詞を使ったオブジェクトの洗い出しを否定します。

オブジェクト指向設計では、まず問題領域に目を向け、そこに存在している名詞を洗い出し、それを表現するオブジェクトを生成するという手法が、半ば公理のように扱われています。その後、これらの名詞に関連した動詞(つまりその操作)を洗い出し、メソッドとして追加することで設計を完成していくわけです。

こういった、名詞と動詞に着目するプロセスには、必要以上に深いクラス階層を生み出してしまう傾向があります。

とのこと。

私自身もそのように教わったし、そういうものだと思ってました。 この本では、共通性/可変性分析手法を採用した方が効率的にオブジェクトの洗い出しができると言います。この手法は Jim Coplien という人がマルチパラダイムデザインという本で紹介しているそうです。

共通性分析

  • 時が経っても変化しにくい構造を見つける
  • 概念上の観点

可変性分析

  • 流動的要素、変化しやすい構造を見つける
  • 実装上の観点

共通性と可変性を洗い出したら、それを概念上、仕様上、実装上の観点からクラス階層に変換し、次に概念間の関連付けをする。流動的要素を見つけ出し、凝集度の高い、結合度の低いクラス内にカプセル化する。

と続いていきます。

ここに出てくる「流動的要素」という言葉はこの本に何回も出てくるので、重要なキーワードだと思います。

流動的要素

この本では流動的要素という言葉がたくさん出てくるので、その一部をここで紹介しておきます。

流動的要素を見つけ出し、それをカプセル化する(P.80)

これは GoF が示唆している優れたオブジェクト指向設計を生み出すための戦略の1つとのこと。 ちなみに戦略はあと2つ紹介されていて、

  • インターフェースを用いて設計する
  • 継承よりも集約を使用する

と書いてあった。

何を変更可能にするのかを考えるのです。ここで着目しているのは、流動的概念のカプセル化であり、多くのデザインパターンのテーマともなっているものです(P.125)

何を変更可能にするのか?

設計の質を測る尺度の1つに、どれだけうまく流動的要素を取り扱えるかという観点があります(P.167)

将来変更されそうなものをうまく扱えたらよさそうです。

クラス内に複数の流動的要素を保持しないという設計目標がある(P.229)

なぜなら、これによって凝集度が高まるとともに、流動的要素間の結合度が低くなるため。

つまり、よい設計のためには、流動的要素 = 変化するものをうまく扱えるようにする必要がある。そうすれば将来の変更に対して強くなれるということでしょうか。また、それをテーマに多くのデザインパターンが導き出されていると。

なんとかの原則

「第14章 デザインパターンの原則と戦略」ではデザインパターンの要となる、ということで、以下の原則についても触れらています。

開放/閉鎖原則(open/closed principle)

拡張性という観点から見た場合、見通しの利くよう(open)になっており、変更という観点から見た場合、閉鎖的(closed)になっているべきということ。つまり、既存クラスに手を入れずに、追加することで拡張できるようにするということのようです。

依存性の逆転原則(Dependency inversion principle)

  • 高次のモジュールは、低次のモジュールに依存してはならない。高次のモジュールと低次のモジュールは、いずれも抽象的側面に依存すべきである。
  • 抽象的側面は詳細に依存してはならない。詳細が抽象的側面に依存すべきである。

難しい・・。下のレイヤーにいる人は上のことを知っているべきだけど、上のレイヤーにいる人は下のことを知らないようにすべき、ということかな。

リスコフの置換原則(Liskov substitution principle)

派生クラスと基底クラスが置換可能でなければならないということ。 この本では、派生クラスの存在すらも隠して型のカプセル化をしたいと書かれている。

まとめ

感想

この本に書いてあるようにオブジェクト指向であれこれ考えたり、そこから導き出されたパターンを使ったりする目的は、すべて開放/閉鎖原則を達成するためという気がした。つまり機能追加等で新しいコードを書くときに、

  • 既存のコードは変更したくない
  • 新しいコードの追加と、それを利用するための最小限の変更のみですませたい

ということなのかな、と思った。 それを達成するために、流動的要素をカプセル化して、クラス/モジュール間の結合度を低くして、凝集度を高めて、小さな責任を持ったたくさんのオブジェクトを作ってものごとを遂行していく。

でも一方で、これはやりすぎに注意しないとな、と思った。将来の変更時に既存コードに手を入れずにすむようにするというのは大変なことなので、考えすぎて必要以上に複雑にならないようにしたい。そういうのも大事だけど、シンプルさも大事だと思う。

今後にどう活かせそうか

  • オブジェクト指向の原則はちゃんと頭に入れておく
  • ただし、それに従いすぎない。いいとこ取りをしていきたい
  • いいところ
    • 3つの観点から考える
    • 共通性と可変性(流動的要素)を意識する
    • 流動的要素をカプセル化して変更に強くなる
    • 継承よりも集約を使う

この本で読んだことはまだ実践で試してないけど、今後機会があったら思い出して参考にしていきたいと思います。

オブジェクト指向のこころ (SOFTWARE PATTERNS SERIES)

オブジェクト指向のこころ (SOFTWARE PATTERNS SERIES)