第2章 共通性分析
共通性と可変性は、ほとんどすべてのソフトウェアパラダイムにとって、主要な特性である。この章では、共通性について調べていこう。共通性はアプリケーションのファミリを定義する。そしてファミリはマルチパラダイム開発におけるソフトウェア抽象の最も基礎的な概念である。 ― 新装版 マルチパラダイムデザイン p.37
2.1 共通性:抽象のエッセンス
p.38
共通性分析は、結合度と凝集度(coupling and cohesion)という設計原理と同調するものだ。ソフトウェア設計では、なるべく個別に作成できメンテナンスできるプロダクトと構築しようと努める。分割がうまくいくと、結合度が低く凝集度の高いプロダクトが作成できる可能性も高くなる(結合度が低いと、チームのメンバが個別に働くことができる。凝集度が高いと、各設計成果が概念的な一貫性を持つものになり、そのシステムは理解しやすいものになる)。
基本的な立場
2.1.1 演繹的共通性と帰納的共通性
p.39
自動車を目にしたことがあるのであれば、それを見たときに、自動車だと認知できる。その年の新式の自動車を見たとしても、これまで見たことのないその実体を自動車だと認知できるのだ。それは自分たちの経験の内にある自動車とは詳細が異なっているが、それでも一般の自動車に共通しているアスペクト(様相)を共有している。
アスペクト(様相)=相貌
2.2.2 設計の認識論
p.46 グラウンデッド理論(grounded theory) http://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%A9%E3%82%A6%E3%83%B3%E3%83%87%E3%83%83%E3%83%89%E3%83%BB%E3%82%BB%E3%82%AA%E3%83%AA%E3%83%BC
2.3 共通性次元と共通性カテゴリ
p.50 共通性の次元の例
- Structure: 構造
- Name and behavior(Identifier、Signature、Type): 名前と振る舞い(識別子、シグネチャ、型)
- Algorithm: アルゴリズム
2.3.1 データ構造
p.53
例えば、Windowはクラスとして適切なものである。これは関連する責務を集めた座(locus)を形成している。
"locus" (Latin for "place" or "location")
ここで言っている「座」がよく分かりません。
2.4.2 名前と振る舞い
p.63
単純なドメインNumberを考えるとしよう。このドメインの中には、operator+、operator-、operator*などの算術演算子のファミリがある。
この記述から、「ドメイン」と「ファミリ」という言葉を理解できる。図2.4(p.50)左側で、Numberを頂点とする階層全体が「Numberドメイン」である。
- Numberドメイン
- Numberとその派生クラスComplexやReal、Imaginaryという個々はサブドメイン
- このドメインに、operatorファミリがある
- operatorファミリの構成員(+や-)を、サブドメインに割り付ける (p.50)
疑問
「共通性分析によって得られるカテゴリ」=「ドメイン」とするならば、共通性分析には様々な次元があって、1つの対象に対して次元ごとにいろいろなドメインを見いだしうる。上の例では、Numberという構造から見たドメインと、operatorという振る舞いから見たドメイン、と言えることになる。この後者をドメインと呼ぶのかどうか、本の用例などを見ると曖昧なように思う。
2.5 共通性分析のレビュー
p.67
共通性分析はカテゴリを生み出す。ここでカテゴリと言っているのはドメインのことだが
共通性分析によって得られるカテゴリ = ドメイン
共通性分析における、自問自答
- ファミリのすべての構成員に対して、真(true)となるものであるのに、いまだ記述されていないような特性が存在しないだろうか。
- 共通性をさらに正確に記述することはできないだろうか。
- 共通性は厳密だろうか。
- 共通性は矛盾しないだろうか。
2.6 共通性とシステム拡張
p.68
我々はドメインの語彙集に定義された構成要素に共通性を探し出すだけでなく、その語彙集が明日になっても今日と同じものであるかどうかを尋ねる必要がある。
時間的にも安定している共通性を探し出すということ
p.69
優れた共通性分析が弾力的な設計を引き出すということは、多くの場合、真であることに違いがない。
@hidenorigoto ここではカテゴリ=ファミリであると思いますが、ドメインとファミリの関係は1.3.5 ファミリと共通性分析 (pp.11-12)に書かれていて、ファミリはドメインといえるが、ドメインはファミリを形成しないものがあるため、必ずしもファミリとはいえない、と理解しました。
@iteman ありがとうございます。ファミリとドメインは、その言葉が指す対象が似ているけれども、表している事柄は違いますね。
分析の基礎的ツールとしての抽象
2.1 共通性:抽象のエッセンス (p.37)
ソフトウェア設計における大きな進歩はすべて、抽象に対する新しい見方の獲得の上に成り立っていることがわかる。抽象というのは、自然言語で普通に使われる場合には、一般性(general)に焦点をあて、特殊性(specific)は取り上げないことを意味している。ソフトウェア開発では、共通しているものは何かを強調し、詳細は省くことにより、抽象化を行っている。抽象化は分析の基礎的ツールである。
抽象とパラダイム
2.1 共通性:抽象のエッセンス (p.37)
「ソートすること」という抽象は、オブジェクトパラダイムから生み出されるものではなく、手続きパラダイムに基づくものだ。しかしそうであっても、それが主要なビジネス上の抽象であることに変わりはない。
抽象はオブジェクトパラダイムのみに由来するものではない。
共通性と抽象
ソートすること
2.1 共通性:抽象のエッセンス (pp.37-38)
ソーティングアルゴリズムを考察する際に、そのデータがランダムに並んでいることがわかったならば、クィックソート(quicksort)を使用しようと考えるだろう。…高レベルの設計ではこのようなアルゴリズムをすべて等しく扱うことができるが、それはこれらに共通点があるからだ。つまり、どのアルゴリズムであっても「ソートする」。ここでは、この共通性が抽象化のベースになっているのである。
行列
2.1 共通性:抽象のエッセンス (p.38)
代数行列のパッケージを作成しているのであれば、行列(matrix)という抽象を考えることができるだろう。もちろん、行列と言っても、さまざまな種類の行列があることを我々は知っている。疎行列、単位行列、上対角行列、下対角行列など。これらはすべて実装が異なる。しかし、共通した振る舞いを持つためにグルーピングすることができる。この場合にも共通性が抽象を可能にしているのである。
- 共通性が抽象化のベースになっている。
- 共通性が抽象を可能にしている。
@iteman
p.57の以下の2つの箇所、英語ではどういう文章なのか分かりますか?
あるいは、表示可能な(displayable)オブジェクトをインスタンス生成するクラスの1つのメンバ関数として、displayOnを定義することもできるだろう。
継承により関係づけられたクラスのファミリの部分として、これらの関数を仕立て上げることもできる。
@hidenorigoto 博士論文のバージョンになりますが、以下のようになります。
Or we could make
displayOna member function of each class whose objects are displayable:Or, we could make them part of a family of classes that we relate by inheritance: ― Multi-Paradigm Design, Ph.D. Thesis p.72
@iteman ありがとうございます。 後者の例は、displayOnは1つのファミリを構成するけれど、それが、別のファミリ(Windowクラス)の部分にもなっている、ということですね。
2.2.2 設計の認識論
p.46 グラウンデッド理論(grounded theory) http://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%A9%E3%82%A6%E3%83%B3%E3%83%87%E3%83%83%E3%83%89%E3%83%BB%E3%82%BB%E3%82%AA%E3%83%AA%E3%83%BC
こちらのリンクもなかなかおもしろかったです。
http://web.cc.yamaguchi-u.ac.jp/~ysekigch/qual/grounded.html
これを読むと、グラウンデッドセオリーも、カテゴリー理論との関わりが大きいのかなと。
p.40 新規に開拓するドメインに対する設計では、最初に行われる直観で行うとも言えるフェーズを省略する。 必要となる原形だけを借りて、ドメイン自身を観察して分割のための鍵を探す。 前もって予想を立てておいた分割基準を用いた問題から抽象を捻りだすのではなく、ドメイン自身から抽象を導き出す。
→ 文章が難解に感じるのですが、「経験的に分からない場合もあるよね」というような単純な話をしていると思っていて良いでしょうか・・・。
p.41 ただし、モジュールがドメインに境界を引くことは必然ではない。 どのようなビジネス概念であっても、その論理的な塊(凝集)と、その概念を表現するプログラミング言語の能力の間には、 テンション(緊張、伸縮)が存在する。
→ 言い換えると、人が理解しやすいもともとの概念レベルでのグルーピングと、構造化したモジュールの境界とでは、成り立ち方がそもそも違うので、自然に一致したりはしない。
【不明点の質問】 p.41, p.42 あたりに出てくる「モジュール」という言葉は、 「パッケージ」(Ruby の Gem や PHP の Composer)とは違う意味なのでしょうか? コンパイル可能なソースコード単位、というような意味なのか、分かりませんでした。 http://www.cc.kyoto-su.ac.jp/~hxm/cstext/prog06.html
p.42 アルゴリズムに関する共通性は多重定義で、振る舞いの共通性はpublic継承で、そして構造上の共通性は集約(aggregation)で表現できる、ということに気づくことがあるだろう。
今まで、自分の中では「アルゴリズム」と「振る舞い」を同じような意味の言葉としてに一緒くたに使っていた(どちらも、手続き、機能、動的、というようなイメージだった)ので、意味を確認。
- アルゴリズム: howのこと。戦略、作戦、方策。
- 振る舞い: 機能。
overload
Scala例(メソッドの多重定義。分数と整数の間で加算を行うメソッド):
class Rational(n: Int, d: Int) {
private val g = gcd(n.abs, d.abs)
val numer = n / g // 分子
val denom = d / g // 分母
def + (that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
def + (i: Int): Rational =
new Rational(number + i * denom, denom)
// 中略
}
p. 42
しかし、まずドメインを見つけるという作業をしなくてはいけない。(中略) これを開始するにあたっては、まず用語辞書を作成する。 そしてこの辞書を使って、ドメインの「ピース」と、全体としてのドメインに意味を帰属させる。
帰属させる?という言葉が分かりにくかったのですが、原文を見て理解しました。
英語論文
To get us started, we develop a dictionary of terms. Using this dictionary, we ascribe meaning to the “pieces” of the domain and to the domain as a whole.
ascribe の単語の意味(English Theasaurus)
ascribe
verb
he ascribed Jane's short temper to her upset stomach:
ATTRIBUTE,
assign, put down, set down, accredit, credit, give the credit for, chalk up, impute;
lay on, pin on, blame on, lay at the door of;
connect with, associate with.
→ 辞書を使うことにより、ドメインのピース群や、全体としてのドメインに対して、意味を与えることができる。
という意味と分かりました。
英語バージョンはこちら↓ですね。翻訳でよく分からなかったときに見てみようと思います。
http://www.netobjectives.com/files/CoplienThesis.pdf
p.60 CRCカード
- 以下、「オブジェクトデザイン」より引用
p.71 2.3.1 CRCカード オブジェクトの候補であれロールの候補であれ、候補についての予備的なアイデアは、CRCカードに記録します。 CRCは、候補(Candidates)、責務(Responsibilities)、コラボレータ(Collaborators)を表します。 このようなインデックスカードは、初期の設計アイデアを探求するのに手ごろなローテクの道具です。 CRCカードの無地の側に、それぞれの候補の目的とロールステレオタイプを、形式にこだわらないで記述します。
文書 <候補 目的:文書はグラフィックとテキストの入れ物として振る舞う <アプリケーションにおける役割 パターン:Compositeパターンのコンポーネント <Compositeパターン内でのロール ステレオタイプ:構造化役 <性格
図 さらに明確にするために、CRCカードの裏側に、候補の知っている責務や行う責務を記録します。
2.3.2 名前と振る舞い
p.60
振る舞いを、意味やセマンティクスとは区別しておくことは重要である。〜 プログラムは、クラスが異なる振る舞いをするにしても同じ意味を持つならば、互換的に使用できなくてはならない。
5.1.4節にこれは「共通のセマンティクス、すなわち意味を背景とする「振る舞いの可変性」である」という記述があります。(p.115)
セマンティクス、意味 = 共通性 振る舞い = 可変性
というくくりになるのかと。
共通性分析の重要な点
2.1 共通性:抽象のエッセンス (p.38)
- 抽象化のサポート
- 設計の中のクラス群を一つの抽象で捉えて設計を進められ、複雑性への対処が可能になる。
- 凝集度/結合度の分析のサポート
- 共通性によるグルーピングでは、互いに独立した塊を自然と作り出すことができる。
- メンテナンスコストの低減
- 強い共通性は、設計上の不変構造(invariant structure)になる可能性が高い。
二つの共通性の認知方法
2.1.1 演繹的共通性と帰納的共通性 (p.39)
- 既知のパターンの認知
- 経験に関係
- 帰納的
- 再利用(ソフトウェア設計)
- 心の中にある「典型的な自動車」が、それを目にしたときに自動車だと認知するのを助けてくれるのである。 -> プロトタイプ理論(認知言語学)
- 設計の基盤としての原形や「枠組み」を築くことができる[Winograd1987]。(ソフトウェア設計)
- 未知の構造の認知
- 学習の一形式
- 演繹的
- 「新規に抽象を生成する」こと(ソフトウェア設計)
- ドメイン自身から抽象を導出(ソフトウェア設計)
ソフトウェアに対する視点というのは、我々が自分の周りの世界を考えることとかけ離れてはいない。
ソフトウェアファミリ
2.1.2 ソフトウェアファミリ (p.40)
データ構造と機能(function)を、構造(structure)、名前(name)、振る舞い(behavior)といった評価基準(共通性次元)に基づいてグルーピングしたもの。
ドメインとモジュール
2.1.2 ソフトウェアファミリ (p.41)
ただし、モジュールがドメインに境界を引くことは必然ではない。
複数のモジュールにまたがるドメインの例としては、フレームワークモジュールがあるドメインの基底クラスを提供し、アプリケーションモジュールがその拡張クラスを作成する、というものが考えられる。OSGiバンドルのような拡張ポイント(例: org.eclipse.ui.views)による同一ドメインの拡張(例: com.piece_framework.makegood.ui.views.resultView)もそのような例の一つといえる。
問題ドメインの構造に沿った解決ドメインの構造
2.1.2 ソフトウェアファミリ (p.41)
そのドメインの重要な次元を、従来のモジュールとして表現するのではなく、つまり、ソースコードの連続した塊やオブジェクトのためのコードに対応する何かとして考えるのではなく、言語の備える構成要素の中でそれを表現していきたい。
これは解決ドメインにおいて問題ドメインの構造(アーキテクチャ)を直接的に表現する(解決ドメインにそのような部分を作る)ことを目指すことだと思う。このことはドメイン駆動設計におけるモデル駆動設計に相当する。
共通性から問題ドメインの構造を導く
2.1.2 ソフトウェアファミリ ドメインを見つけること (p.42)
行列を2つのサブドメイン(行列セマンティクスのサブドメインとメモリ管理のサブドメイン)に分けることから、アーキテクチャを導くことができる。そのアーキテクチャでは、モジュールに高い凝集度を持たせることが容易で、関心を分離しないで考えた場合よりも、管理に独立性を持たせることができる。
共通性分析によって問題ドメインの構造(アーキテクチャ)を作る。
ドメインの語彙
2.2 分析を始めるにあたって:ドメインの語彙を定義する (p.43)
- プロジェクトのコミュニケーションのため
- 分析の概念をソリューションの構成要素に変換する時に活用するため
- 意図を持った設計(~~intensional~~ intentional design -> こちらを参照のこと)を支援するため
- 実世界の関心を反映する構造を生成することを容易にするため
ドメイン辞書
2.2.1 ドメイン辞書 (p.43)
- これから解決しようとする問題に絡むすべての側面を把握するため
- ソリューションのすべての側面を把握するため
ドメイン辞書は、その問題領域における技術用語のカタログであり、設計者はこのカタログに記載されている用語を使って作業を進める。
ファミリのために設計する
2.2.1 ドメイン辞書 (p.43)
問題に初めてアプローチするとき、設計者が直面するのは目の前にあるニーズである。ソフトウェア開発の作業の大部分は、明示された問題により発生する。そしてそのような問題は、顧客自身の問題である。このようなニーズの性質から、アプリケーションはその顧客の問題に特化したものになる。問題文の大部分がこのようなものであることから、共通性を見つける機会は制約を受けることになる。
広い領域に適用できるソリューションを考えるには、この制約を打ち破らなければならない。
対象のスコープを広げれば、考慮対象のドメインにおける共通性を見つけるという機会を増大させることができる。つまり、アプリケーションのファミリのために設計するのである。そのファミリの原形となる構成員の1つとして、その初期アプリケーションを手作りしようと考える。
あるアプリケーションを作る際に、そのアプリケーションをフレームワーク(手作りでもよい)とその最初のクライアントという構成に意図的に持ち込むことで、共通性を見つける機会の制約を打ち破り、広い領域に適用できるソリューションを作り出そうということである。このときアプリケーション分析ではなくドメイン分析を行うことになる。
ドメイン分析のメリット
2.2.1 ドメイン辞書 (p.43)
- 一般性
- レジリエンス(resilience)
ライブラリ・フレームワークとドメイン分析
多くのライブラリやフレームワークの開発においては実質的にドメイン分析が行われているといえると思う。
可変性分析
2.2.1 ドメイン辞書 (p.44)
- 共通性分析から得られる汎用性を補足
- 変更に対する回復力を追加
汎用性とトレードオフ
2.2.1 ドメイン辞書 (p.45)
またこのとき、実行時にその汎用性と引き換えに、何かを犠牲にするという必要もない。事実、実務の中では、共通性分析と可変性分析を完全に分離することはできない。柔軟性、変更への回復力、汎用性は、互いに密接に関係しているのである。
汎用性の高いソフトウェアは柔軟性に欠けるという意見をよく見かけるが、決してそうではないということ。
用語のトレーサビリティ
2.2.2 設計の認識論 (p.47)
ドメイン辞書に載っている用語は、要件定義ドキュメントの中で下線を引いておこう、というのが、FASTの提案である[Weiss+1999]。
問題ドメイン分析と解決ドメイン分析
2.3 共通性次元と共通性カテゴリ (p.48)
アプリケーションドメインの中でまずこれを行い、そのあとからソリューションドメインの中で同じことを行うということも可能かもしれない。しかし実際には大部分の設計者がこれを同時に行っている。アプリケーション分析を実施している最中に、ソリューションドメインを考えるという場合には、C++の形をしたナイフを使って、アプリケーションドメインを切り取っているのだ。そのために、問題の構造をC++のソリューションで表現することがかなり容易にできる。
例えば、DOAをソリューションドメインと見ると、DOAの形をしたナイフを使って、アプリケーションドメインを切り取っているということになる。その結果作られる概念モデルはソリューションから独立したものではないと思う。
共通性分析・可変性分析と共通性カテゴリ
2.3 共通性次元と共通性カテゴリ (p.50)
この2つの次元、つまり、基本的な共通性の次元と基本的な可変性の次元の2つを組み合わせてはじめて、共通性カテゴリ(commonality category)を記述することができる。共通性カテゴリに、バインディング時期、インスタンス化の可能性、デフォルト値に対する要件を組み合わせれば、そのカテゴリに適したC++言語機能を指定することができる。
共通性分析と可変性分析の実施タイミング
2.3 共通性次元と共通性カテゴリ (p.51)
共通性分析と可変性分析は、実際には分離できるものではない。事実、可変性は共通性から導出することができる。そこで、共通性の次元軸に沿って可変性を調べることができる。可変性の次元は、共通性を探すために使った軸と同一である。
抽象データ型
2.3 共通性次元と共通性カテゴリ 2.3.1 データ構造 (p.52)
オブジェクトパラダイムでは、意味的に関連性を持つアクティビティをグルーピングしてメンバ関数と呼び、それを使ってクラスと呼ばれる抽象を作成する。このクラスという抽象は、データ構造を持つのが一般的である。しかし、そのデータ自身やデータがシステムをどのように流れるかにはあまり関心を寄せないで、そのデータに関連する操作がどのように結びつけられるかに多くの注力を払う。関連する操作こそがこの抽象を形成しているのだが、この抽象を抽象データ型(abstract data type)と呼ぶ。
責務駆動とデータ構造
2.3 共通性次元と共通性カテゴリ 2.3.1 データ構造 (pp.52-53)
このような手法では、システムをかたどる振る舞いをグルーピングすることに焦点をあて、コードを形作るデータやアルゴリズムの詳細にはあまり注力されない。
共通性カテゴリと現代のカテゴリ理論
2.5 共通性分析のレビュー (p.67)
共通性分析が生み出すカテゴリ(ドメイン)は古典的モデルに見られる数多くの特性(カテゴリ同士は連結しないのが普通で、すべてのカテゴリ構成員に傑出してみられるような特性)を有しているが、この結果に対してプロトタイプ理論や基本的カテゴリ等に立脚する分類から得られる特性を持たせることができる。
時間が経過しても安定している抽象を切り出す
2.6 共通性とシステム拡張 (p.68)
そこで、共通性分析をする際には、時間が経過しても安定している抽象を切り出すように努める必要がある。このことは、共通性分析が分析者の知識の上に実施されるということを意味している。時間の経過につれてドメインがどのように変化するかを、分析者が知っている必要があるのだ。
読書会での説明が言葉足らずだった部分もあるかと思いましたので、C/C++コードに関しての補足を置いておきます。
はじめに
- C++にはメンバ関数とフリー関数(非メンバ関数、あるいは単に関数)の2つがある。クラス定義の中で宣言されていればメンバ関数、そうでなければフリー関数。
- メンバ関数はオブジェクトパラダイムに、フリー関数は手続き型パラダイムに由来。
class Foo {
void bar(); // メンバ関数
};
void buzz(); // フリー関数
...
Foo f;
f.bar(); // メソッド呼び出し。objectが必要
buzz(); // フリー関数
2.4.1 構造
p.61 typedef
typedef struct _Point { int xpos; int ypos; } Point;
- xpos, yposをメンバとする_Point構造体を定義する
- "struct _Point"型に"Point"という別名(alias)を付ける
という2つを行っている。以下の(1)(2)はまったく同じ意味。
struct _Point p; // (1), C言語時代のdefault syntax
Point p; // (2), typedefするとこう書ける
こういった構造体定義の書き方をするのはC言語のみで、C++では素直に以下のように書く。
struct Point { int xpos; int ypos; };
Point p;
p.62 List
http://ja.wikipedia.org/wiki/連結リスト アルゴリズムドメインの言葉としては、ListRepではなくNodeのほうが適切ではないかと思う。intを格納する片方向連結リストをC++で素直に実装してみる。
class Node {
int data;
Node *next;
};
class List {
public:
...
private:
Node* first_node;
};
何を格納するのかによってint dataの箇所だけ変える必要があり、それに依存してNode型のサイズも変わるが、他の部分はすべてのListで共通している。こういった場合、テンプレートクラスを使うことで類似性を表現できる。
template <class X> class Node {
X data;
Node *next;
};
template <class X>
class List {
public:
...
private:
Node<X>* first_node;
};
Listを使う場所ではXがどの型なのかを明示する必要がある。
List<int> int_list;
List<Point> point_list;
人間がIntList, PointList...といったコピペクラスを量産する代わりに、コンパイラが内部でList<X>のコピペを生成している。所詮ただのコピペなので、実体化したクラスの数に比例してオブジェクトコードは膨張するし、List
2.4.2 名前と振る舞い
(C++コード的な意味で)2章最難関。
p.63 operator +とoperator +=
operator+=という名前も「加える」という意味を表し、さらに代入操作が組み合わされている。 継承階層で定義すれば、再定義の仮想関数を使って、実行時にoperator+をバインドすることができる。
フリー関数の呼び出しは静的に解決されるため、どのoperator +が呼ばれるのかはコンパイル時点で決まってしまう。実行時バインドを実現するためにoperator+から仮想メンバ関数のoperator+=を呼び出すことで、実行時の型に合わせて加算アルゴリズムを呼び分けている(p.64中段のコード)。
p.64 多重定義アプローチ
後者のアプローチでは、以下のようなコードシーケンスを処理できないことには注意しよう。
int i; Complex a, c; a = i + c;しかし、多重定義アプローチはこれを処理することができる。Complexに、doubleもしくはintを受け付けるコンストラクタを持たせるようにすればよい。
operator+=は左辺に対して定義する必要があるが、C++ではintなど組み込みの型に対してメソッドを定義できないため、そのままでは上手く扱えない。 そこで、intを引数に取るComplexのコンストラクタを定義することで、int => Complexへの変換を発生させ、operator+の中ではメソッドを持ったComplexオブジェクトとして扱うようにする。
class Complex {
public:
Complex(); // (1) デフォルトコンストラクタ
Complex(int n); // (2)
};
void foo(const Complex& c);
Complex operator + (const Complex &n1, const Complex &n2); // (3)
...
int i;
Complex a; // (1) が実行
Complex c(2); // (2)が実行
a = i + c; // (2)が実行、int=>Complexの暗黙変換が発生。その後(3)が実行
ここでいう多重定義アプローチは、p.63で挙げていたoperator+の多重定義ではなく、Complexのコンストラクタの多重定義の話。 ちなみにこの例は暗黙の型変換を活用するコードで、2015年現在では行儀が悪いとされる。素直にOperator + (int n1, const Complex& n2)を定義するほうが良い。 参考:wikipedia:型変換#組込みの型変換とユーザ定義の型変換
2.4.3 アルゴリズム
p.65
void FloorPlan::redraw(void (FloorPlan::*f)() = 0) {
...
if (f) (this->*f)();
...
}
"戻り値無し、引数無しのFloorPlanクラスのメソッド"を引数にとるメソッド。fは仮引数。 (this->*f)()でメソッドを呼び出している。
p.66 バインディング時期
C++では「値」「参照」「ポインタ」の3通りの方法でオブジェクトにアクセスできる。
| 宣言 | 呼び出し | メソッド解決 | |
|---|---|---|---|
| 値 | X n; | n.bar() | 静的 |
| 参照 | X& n; | n.bar() | 動的 |
| ポインタ | X* n; | n->bar() | 動的 |
メソッドが仮想関数で、かつ参照/ポインタ経由で呼び出した場合にのみ実行時バインディング。それ以外のケースではコンパイル時バインディング。 余談ですが、本書のコードのように
FloorPlan *q = new FloorPlanWithArrows():
q->redraw();
と書くと、コンパイラの最適化でコンパイル時にバインドする場合があります。(qが明らかにFloorPlanWithArrowsを指しているため)
@nyanp ありがとうございます。大変参考になります。
共通性分析の目標
第3章 可変性分析 3.2 共通性ベース (p.73)
共通性分析には2つの目標があった。1つはシステムの主要構造の軸を見出すこと。もう1つは可変性分析を可能とする背景を提供することである。
オフトピックですが、自分が日本語で馴染みのなかった言葉の原文を確認しました。
p.39
抽象を「定式化」?
↓ formulate 1 〈理論計画考えなど〉を明確に[系統的に]組織化する, (細部にわたり)練り上げる (実施の細目まで決定することを含む) ; …を公式[定式]化する, 明確に表現する
ドメインの語彙を「形式化」?
↓ formalize 〈計画決定など〉を正式[公式]なものにする; 〈考えなど〉を明確にする.
データ分析とオブジェクト指向分析
2.3 共通性次元と共通性カテゴリ (pp.53-54)
ここから、いくつかの教訓を得ることができる。データ構造に主眼を置くような設計は、責務分配に基づく設計とはまったく異なるものになるだろう。データ構造が設計での重要な考察項目でないと言っているのではない。データ構造が実装上の構成要素であったにしても、優れた設計というものは設計での決定事項をどのように実装するかを調査するものなのである。データ分析とオブジェクト指向分析を同一視しようとする新古典派手法の落とし穴に陥ることなく、この2つの共通性に関する次元を分離し、設計ではそのそれぞれを扱っていく必要がある。
データ構造という設計次元に対して、データ分析のデータ構造とオブジェクト指向分析のデータ構造として分離し、それぞれ別に扱っていく必要があるということだろうか。
オブジェクト指向分析はデータ分析よりもデータ設計に優れているか?
2.3 共通性次元と共通性カテゴリ (p.54)
悪を取り除こうとして善をも取り除いてしまうことがないように、データ設計が優れたオブジェクト分割と同等である場合も多いことを指摘しておこう。ここで主張してきたのは、そのことを当たり前と仮定してしまってはいけないということである。正しい手段によってそのようになるように心がけるべきだ、と言ったほうが適切だろう。
未知の構造の認知
2.1 共通性:抽象のエッセンス 2.1.1 演繹的共通性と帰納的共通性 (pp.38-39)
既知のモデルがうまく適用できない。新しい状況に直面したときには、再現性を探しだして抽象を形成する。アナロジも経験も存在しないケースでは、演繹的な論法を使って、モデルと抽象を作成することになる。見知らぬ文化の住居を初めて目にしたならば、その住居のいずれもがどこか似ているような印象を持つのではないだろうか。つまり、「その文化のための住居」という認識の抽象が定義される。これとまったく同じことが、ソフトウェアに対しても行われるのである。 マルチパラダイムデザインは、ドメインエンジニアリングの経験を利用して、一般に認知されているドメインへと問題を分割する。設計が進行するにつれてドメインに描き込むものが増えていくが、それは貯蔵されていたものが分配されるというのとは異なる。新規に開拓するドメインに対する設計では、最初に行われる直観で行うとも言えるフェーズを省略する。必要となる原型だけを借りて、ドメイン自身を観察して分割のための鍵を探す。前もって予想を立てておいた分割基準を用いて問題から抽象を捻りだすのではなく、ドメイン自身から抽象を導き出す。あるアプリケーションにとってたまたま既存のあるパラダイムが最も優れた選択であるということになった場合に、共通性/可変性分析はその選択の正しさを補強してくれるだろう。