読書メモ:オブジェクト指向のこころ

読書メモ:オブジェクト指向のこころ

October 1, 2022

以下の本を読んだ。あとで見返したいところについてメモを残しておく。


第 1 章:オブジェクト指向パラダイム #

変更の要求に取り組む - P.9 #

要求の変更によって引き起こされる問題に取り組むため、そして機能分解以外の解決策の有無を見極めるために、人間の行動に目を向けてみましょう。とある大学で開催されるセミナーの講師として、あなたが任命されたと考えてください。あなたの講義を聞き終わった学生は、次のセミナーが行われる教室に移動しなければなりませんが、それは各人によってまちまちであると仮定します。そしてあなたは、聴講学生各人に対して次の教室への行き方を教えなければならないとします。

構造化プログラミングのアプローチを取った場合、この作業は以下の手順になるはずです。

  1. 聴講学生のリストを取得する。
  2. リスト上の各学生に対して、以下の処理を行う。
    1. その学生が聴講する次のセミナーを調べる。
    2. そのセミナーが行われる教室を調べる。
    3. あなたのいる教室から次のセミナーが行われる教室までの行き方を調べる。
    4. その学生に次の教室への行き方を伝える。

そしてこの手順を実行するには、以下の手続き群が必要となるはずです。

  1. あなたのセミナーを聴講している学生のリストを取得する機能
  2. あなたのセミナーを聴講している各学生のスケジュールを取得する機能
  3. あなたのいる教室から他のセミナーが行われる教室に行く方法を教えるプログラム
  4. あなたのセミナーを聴講している学生毎に、定められた手順を実行する制御プログラム

実際には、こんなことをしないはずです。おそらく、あなたは今の教室から他のセミナーが行われる教室に行く方法を記したポスターを貼り、聴講している学生全員に「この教室の後ろに、次のセミナーが行われる教室とそこへの行き方を説明したポスターを貼りました。次の教室に行く際の参考にしてください」と言うのではないでしょうか。各学生は自分が受講する次のセミナーを知っているはずであるため、ポスターを見ればそのセミナーが開かれる教室を見つけることができ、その教室に移動する方法が判るはずです。

これらのアプローチの違いは何でしょうか?

  • 各学生に対して明示的に行き先を教えるという最初のアプローチは、さまざまな詳細に注意を払う必要があります。あなたはすべてのことに責任を持ち、あなた以外に責任を持ってくれる人はいないのです。これではあなたの身が持たないはずです!
  • 2つ目のアプローチは、一般的な指示を出し、各学生が自力で何とかすることを期待するというものです。

最も大きな違いは責任の移行(shift of responsibility)です。最初のアプローチでは、あなたはすべてのことに責任を持つことになります。2番目のアプローチでは、学生が自身の振る舞いに責任を持つことになります。どちらのアプローチでも実装する作業は変わりませんが、その構成は大きく異なっているのです。

責任を構成し直した効果を確認するため、新たな要求が出てきた場合のことを考えてみましょう。

聴講学生に大学院生がいた場合、その人にちょっとした仕事をやってもらうことになったと考えてください。あなたのセミナー のアンケート結果用紙を集めてもらい、次のセミナーが行われる教室に向かう前にセミナー事務局に届けてもらおうというわけです。最初のアプローチの場合、制御プログラムを修正して、各学生が大学院生であるかそうでないかを判断し、大学院生の場合には特別な指示を行うことになります。このアプローチでは、プログラムの修正量が大きくなる可能性があります。

しかし2番目のアプローチでは、学生が自らの行動に責任を持つことになるため、大学院生の場合のルーチンを追加するだけで済むのです。制御プログラムは、各学生に対して「次のセミナーが行われる教室に向かってください」と告げるだけで済むわけです。これだけで各学生は、自分自身で必要な行動をとることとなります。

これは、制御プログラムから責任が取り去られるということを意味しています。最初のアプローチでは、新たな種類の学生が追加されるたびに、制御プログラムを修正する必要があります。制御プログラムは、新たな種類の学生に何をするかを指示する責任があるのです。2番目のアプローチでは、新たな種類の学生が追加されても制御プログラムに影響は及びません。学生自身が自らの行動を決定する責任を持っているのです。

こういったことを裏で支えているのは、次の3つのことです。

  1. 学生は自身の振る舞いに責任を持っています。彼らの振る舞いを決定する責任を持った中央集権的な制御プログラムは存在していません。(こういったことを実現するには、学生自身が自らの種類を知っていなければならない点にご注意ください。)
  2. 制御プログラムは、さまざまな種類の学生(学部生や大学院生)に分け隔てなく語りかけることができます。
  3. 制御プログラムは、教室から教室に移動する際に、各学生が行うことを知っておく必要がありません。

この意味合いを完全に理解するためには、まず最初に、いくつかの用語を知っておく必要があります。UML Distilled(Addison-Wesley, 1999)の著者である Martin Fowler は、ソフトウェア開発プロセスにおける3つの異なった観点を解説しています。

  1. 概念(conceptual)
    • この観点は、調査対象領域における概念を表現したものです。そして概念モデルは、概念を実装するソフトウェアとは関係なく導き出されるべきものです。この観点は「私は何に対して責任があるのか?」という質問に答えるものです。
  2. 仕様(specification)
    • ここではソフトウェアを考慮することになります。しかし考慮する対象はソフトウェアの実装ではなく、ソフトウェアのインタフェースです。この観点は「私はどのように使用されるのか?」という質問に答えるものです。
  3. 実装(implementation)
    • この時点ではソースコード自体を考慮することになります。これが最もよく使用される観点ですが、多くの場合は仕様という観点の方が優れています。この観点は「私はどのようにして自身の責任を全うするのか?」という質問に答えるものです。

先ほど紹介した「次のセミナーが行われる教室に向かってください」という例をもう一度見てみましょう。講師としてのあなたは、学生と概念レベル(conceptual level)でコミュニケーションを図っていると言う点にご注意ください。言い換えれば、あなたは学生に対してどうするかではなく、何をして欲しいかを告げているのです。しかし、学生が次のセミナーに向かう方法は極めて具体的です。彼らは特定の指示に従うことによって実装レベル(implementation level)で作業をしていることになるわけです。

あるレベル(概念)でコミュニケーションを図り、他のレベル(実装)でそれを遂行することにより、リクエストする側(講師)は何が起こるのかを正確に知らなくてもよくなり、何が起こるのかという概略(つまり概念)だけを知っておけばよくなるのです。これは非常にパワフルな考え方となります。リクエストする側に概念を残したまま、実装詳細に発生する変化からリクエストする側を保護できるわけです。では、こういった考え方を採用し、そこから生まれる利点を活かしてプログラムを作成する方法を見ていくことにしましょう。

オブジェクト指向パラダイムは、オブジェクトという概念を中心に据えたものの考え方です。このため、オブジェクトという観点からすべてのものごとを見ることになります。つまり、問題領域を機能に分解していくのではなく、オブジェクトに分解していくわけです。

オブジェクトとは何でしょうか?従来の考え方では、オブジェクトはメソッドを伴うデータとして定義されていました。しかし残念なことに、こういった狭い視野でオブジェクトを捉えてしまうと、オブジェクトは本来の実力を発揮することができなくなるのです。

オブジェクトを洗い出すには、オブジェクトというものが責任を伴ったものであると考えるのが一番の近道です。優れた設計におけるオブジェクトは、明確に定義された責任を自分自身に保持しています。学生オブジェクトが、次の会場に向かう方法を知っているという責任を持っているのは、こういった理由があるためです。

Fowler の観点からオブジェクトを見ることもできます。

  • 概念レベルにおいて、オブジェクトは責任の集合となります。
  • 仕様レベルにおいて、オブジェクトはその他のオブジェクトや自ら起動することができるメソッド(振る舞い)の集合となります
  • 実装レベルにおいて、オブジェクトはコードとデータ、そして、それら相互の演算処理となります。

オブジェクト指向設計について教えたり議論する場合、概念レベルや仕様レベルという観点からではなく、コードとデータ云々という実装レベルで行われることがしばしばあります。しかし、オブジェクト指向を概念レベルや仕様レベルから考察することにより、素晴らしい力を引き出すことができるようになるのです!

第 13 章:パターンによって解決する #

パターンで考えるための手順 - P.206 #

  1. パターンの洗い出し
    • 問題領域に存在するパターンを見つけ出します。
  2. パターンの分析、適用
    • 分析するパターン群毎に、以下を実行します。
      1. パターンの並び替え(コンテキスト生成順)
        • パターンがどのように他のパターンのためのコンテキストを生成するのかに従って、パターンの並べ替えを行います。これは、あるパターンが他のパターンのためのコンテキストを生成することはあっても、2つのパターンが互いのコンテキストを生成しあうようなことはないという考え方に基づいています。
      2. パターンの選択と設計の拡張
        • 並べ替えた順にパターンを用いて、高次の概念設計を行います。
      3. 追加のパターンの洗い出し
        • 分析中に出てきた追加のパターンを洗い出します。それらも分析対象のパターンに追加します。
      4. 繰り返し
        • すべてのパターンを概念設計に統合するまで、繰り返します。
  3. 詳細の追加
    • 必要に応じて設計に詳細を追加します。メソッドとクラス定義の拡張も行います。