More Related Content Similar to オブジェクト指向入門4 (20) More from Kenta Hattori (20) オブジェクト指向入門42. 2011/2/28 オブジェクト指向プログラミング入門 4 2
オブジェクト技術への道
機能による分解
トップダウン法による開発
機能は一つではない
トップを見つける
現実のシステムにはトップが存在しない
機能と進化
システムが進化するにつれて機能が変更される可能性
インタフェースとソフトウェア設計
早すぎる順序付け
再利用性を推進しない(上位の要求に依存するので)
生産と記述
すでに理解している事柄を説明するのには向いている
オブジェクトによる分解
拡張性
再利用性
互換性
オブジェクト指向によるソフトウェア開発
課題
オブジェクトの型をさがす
型とオブジェクトを記述する
関係とソフトウェアの構造化を記述する
4. 2011/2/28 オブジェクト指向プログラミング入門 4 4
オブジェクトの適切な表現
3つの条件を満たす手法が必要
その記述はあいまいさがなく厳密でなければなら
ない
その記述は完全でなければならない.あるいは,
少なくとも,個々のケースについて期待される程
度の完全さがなければならない.
その記述は過剰仕様過剰仕様( overspecifying )であって
はならない
最後の条件を満たすことが難しい
オブジェクトの本質的な属性を記述する必要があ
る
5. 2011/2/28 オブジェクト指向プログラミング入門 4 5
例:スタックの表現
ARRAY_UP:
配列 representation と整数 count によって表されるスタッ
クで, count の値の範囲は 0 から capacity まで. capacity
は配列のサイズ.要素は 1 から上に向かって count までの
位置に格納される
ARRAY_DOWN:
配列の最後から要素が格納される.スタックの要素は配列
のインデックス capacity から下に向かって free+1 までの
位置に格納される.
LINKED:
2つのフィールドから成るセルに個々のスタック要素を格
納する連結表現.
8. 2011/2/28 オブジェクト指向プログラミング入門 4 8
スタックの表現例: LINKED
プッシュ操作
new(n)
n.item := x
n.previous := last
last := n
item
previous
item
item
item
last
previous
previous
previous
9. 2011/2/28 オブジェクト指向プログラミング入門 4 9
過剰仕様の危険性
これらの表現のいずれかをスタックの「唯一の」定
義として選ぶことは過剰仕様の典型的なケースの 1
つ
例えば,配列と整数と count と上限という ARRAY_UP の
特徴的な属性は,スタックの本質的な構造の理解とは無関
係
特定の表現をしようとして使うことが悪い理由
ソフトウェアのコストの 17% 以上がデータ形式の変更を
考慮する必要から発生する( Lientz と Swanson による)
柔軟性の高いソフトウェアを生み出せない
システムアーキテクチャの基礎としてオブジェクト
型を使おうとする場合,物理的表現よりも優れた記
述基準を見出さなければならない
10. 2011/2/28 オブジェクト指向プログラミング入門 4 10
保守コストの内訳
42%
18%
12%
9%
6%
6%
4% 3%
ユーザ要求の変更
データフォーマットの変更
緊急の修正
定期的なデバッグ
ハードウェアの変更
ドキュメント作業
効率性向上のための修正
そのほか
出典: [Lientz 1980]
11. 2011/2/28 オブジェクト指向プログラミング入門 4 11
オブジェクトを抽象的に見るには
操作を使う
スタックの例の場合,「入れ物」構造を表している
特定の操作を適用できる
スタックの一番上に要素をプッシュする( put )
スタックが空でなければ,スタックの一番上の要素を取り除
く( remove )
スタックが殻でなければ,一番上の要素が何か調べる
( item )
スタックが空かどうかを判定する問合せ
空のスタックを用意する( make )
特定の属性を与えることができる
スタックの容量
12. 2011/2/28 オブジェクト指向プログラミング入門 4 12
名前の一貫性
「入れ物」という高いレベルでのデータ構造を見る
ため
スタックは入れ物の種類の 1 つに過ぎない
正しい名前を選ぶことは再利用可能なソフトウェア
にとって重要
何万もの操作が提供されているライブラリでは系統的で明
確な分類学的命名法が必要
一般的なスタック操作名 ここで使われている名前
push put
pop remove
top item
new make
13. 2011/2/28 オブジェクト指向プログラミング入門 4 13
仕様記述を形式化する
非形式な記述では不十分
put はスタックの「一番上に」要素をプッシュする,
remove は「最後にプッシュされた」要素をポップす
る, etc.
これらの操作が顧客に対して何をするかを詳細に知
る必要がある
抽象データ型( ADT )の仕様情報は以下から構成
される
TYPES (型)
FUNCTIONS (関数)
AXIOMS (公理)
PRECONDITIONS (事前条件)
14. 2011/2/28 オブジェクト指向プログラミング入門 4 14
型を記述する
型とは関数,公理,事前条件によって特徴づけられ
るオブジェクトの集合である
抽象データ型は1つのオブジェクト(特定の 1 つの
スタック)ではなく,オブジェクトの集合の 1 つ
(すべてのスタックの集合)である
ADT の仕様記述によってあらわされたオブジェクト
の集合に属するオブジェクトは,その ADT のイン
スタンスである
● STACK[G]
TYPES
15. 2011/2/28 オブジェクト指向プログラミング入門 4 15
総称性
STACK[G] の G は任意の制約されていない型
を表す
G は抽象データ型 STACK の仮総称パラメー
タと呼ばれ, STACK は総称的 ADT である
という
STACK は型ではなくて型のパターン
スタック型を得るためには,仮パラメータ G に対
応する実総称パラメータを与える必要がある
「総称的に派生した( generically derived )」型
STACK[ACOUNT] は型となる
STACK[STACK[ACOUNT]] という型もあり
16. 2011/2/28 オブジェクト指向プログラミング入門 4 16
関数を列挙する
ADT のインスタンスに適用可能な操作をリ
ストアップする
関数のシグネチャのみの記述
● put: STACK[G]×G → STACK[G]
● remove: STACK[G] → STACK[G]
● item: STACK[G] → G
● empty: STACK[G] → BOOLEAN
● new: STACK[G](→ STACK[G] の省略形)
FUNCTIONS
直積
部分関数
17. 2011/2/28 オブジェクト指向プログラミング入門 4 17
関数の分類
ある型Tについての操作は,以下のように分類可能
生成関数:
矢印の右側にだけ T が現れる new などの関数
問合せ関数:
矢印の左側にだけ T が現れる item や empty などの関数
コマンド関数:
put や remove など矢印の両側に T が現れる関数
18. 2011/2/28 オブジェクト指向プログラミング入門 4 18
AXIOMS (公理)
関数の値を与えるのではなく,それらの値の
属性を記述する
任意の x: G, s: STACK[G] について以下が成り立つ
A1 ● item(put(s,x)) = x
A2 ● remove(put(s,x)) = s
A3 ● empty(new)
A4 ● not empty(put(s,x))
AXIOMS
一番上の要素を取り
出すとプッシュする
前のスタックに戻る
一番上の要素は最後
にプッシュした要素
19. 2011/2/28 オブジェクト指向プログラミング入門 4 19
スタックについて知っている2,3
のこと
ADTの仕様記述は暗黙的なものである
適用可能な関数という形でオブジェクトの集合を暗
黙的に定義する.オブジェクトが何であるかではな
く,どんな性質を有しているかによってオブジェク
トを定義する
列挙されている操作だけがすべてではない
関数そのものもまた暗黙のうちに定義される.明示
的な定義の代わりに,公理を使って関数の属性を記
述する
列挙されている属性だけがすべてではない
20. 2011/2/28 オブジェクト指向プログラミング入門 4 20
部分関数
remove と item
スタック集合の全ての要素に適用できるわけではない
空のスタックからはポップできない,一番上の要素もない
そのような関数は部分関数として記述
⇔ 全関数
部分関数の例:
inv(x) = 1/x
inv: R → R
inv の定義域は R-{0}
remove や item の定義域をどうやって記述したらよ
いか?
21. 2011/2/28 オブジェクト指向プログラミング入門 4 21
事前条件
すべての操作をすべてのオブジェクトに適用
できるわけではない
require 句では,その関数の定義域に入るた
めに引数が満たさなければならない条件を示
す
● remove(s: STACK[G]) require not empty(s)
● item(s: STACK[G]) require not empty(s)
PRECONDITIONS
22. 2011/2/28 オブジェクト指向プログラミング入門 4 22
完全な仕様記述
TYPES
● STACK[G]
FUNCTIONS
● put: STACK[G]×G → STACK[G]
● remove: STACK[G] → STACK[G]
● item: STACK[G] → G
● empty: STACK[G] → BOOLEAN
● new: STACK[G]
AXIOMS
任意の x: G, s: STACK[G] について以下が成り立つ
A1 ● item(put(s,x)) = x
A2 ● remove(put(s,x)) = s
A3 ● empty(new)
A4 ● not empty(put(s,x))
PRECONDITIONS
● remove(s: STACK[G]) require not empty(s)
● item(s: STACK[G]) require not empty(s)
23. 2011/2/28 オブジェクト指向プログラミング入門 4 23
真実以外の何物もない
過剰仕様にならずにデータ構造の本質的な属性をと
らえる
さきほどのスタックの仕様記述は,一般的なスタックとい
う概念について知っておくべきことをすべて表している
代数学を用いて複雑な操作の並びを記述できる
計算を実行する過程は代数学の簡約化と同じ
ADT の公理を使って複雑な式を簡約化できる
記号的な操作のみで可能
item (remove (put (remove (put (put (remove (put (put (put
(new, x1), x2), x3)), item (remove (put (put (new, x4), x5)))),
x6)), x7))) = ?
25. 2011/2/28 オブジェクト指向プログラミング入門 4 25
クラス
オブジェクト指向システムは,部分的あるいは完全に実装され
た相互に作用する ADT の集合として構築される
クラスを得るためには, ADT を準備し,実装を決めなければな
らない
有効クラスを得るためには,実装に関する詳細をすべて用意し
なければならない
クラスは(部分的であっても良い)実装を伴う抽象データ型である
完全に実装されているクラスを有効クラス( effective class )という.部分
的にしか実装されていないか,全く実装されていないクラスを暫定クラス
( deferred class )という.クラスは暫定クラスか有効クラスのいずれかで
ある.
定義:クラス
定義:暫定クラスと有効クラス
26. 2011/2/28 オブジェクト指向プログラミング入門 4 26
有効クラスの作成方法
有効クラスの構成
E1 ADT の仕様記述
E2 表現の選択
E3 関数( E1 )から表現( E2 )への対応
特性と呼ばれるメカニズムの集合として表される
例:スタックの表現
<representation,count>
representation は配列, count は整数
例: put の実装
put(x: G) is
do
count := count + 1
representation[count] := x
end
27. 2011/2/28 オブジェクト指向プログラミング入門 4 27
暫定クラスの役割
暫定クラスは分析と設計に役立つ
オブジェクト指向分析では,実装に関する詳細は全く必要
とされない.
オブジェクト指向設計では,実装の多くの側面を無視する
ことができる.設計においては,システムの高レベルの
アーキテクチャの属性に集中すべきである.
設計を助序に完全な実装に近づけていくにつれて,より多
くの実装の属性が追加され,最終的には有効クラスになる
関連する種類のオブジェクトのグループを暫定クラ
スとして分類することで,以下の重要な役割を果た
す
高レベルの再利用可能なモジュールを提供
複数の変形に共通する振る舞いを把握
ソフトウェアアーキテクチャが非集中的で拡張可能である
ことを保証
29. 2011/2/28 オブジェクト指向プログラミング入門 4 29
より命令的な見方を取り入れる
put: STACK[G]×G → STACK[G]
適用的な見方:
スタックと要素を受け取り,新しいスタックを返す操作
オブジェクトを変更できる操作
G 型の引数を受け取るルーチン.新しいスタックを生成する代わり
に,スタックの一番上に新しい要素をプッシュし,スタックを修正
する.
ADT の公理
ルーチンの事後条件という句なる
put(x: G) is
require … (事前条件)
do … (ルーチンの実装)
ensure
item = x
not empty
end
30. 2011/2/28 オブジェクト指向プログラミング入門 4 30
オブジェクト指向によるソフトウェ
ア構築
基本は抽象データ型( ADT )という概念
ソフトウェアに必要なのは数学的な概念としての ADT ではなく,ソフトウェア
の概念である ADT の実装
実装は完全である必要はない
システムはクラスの集合である.トップやメインプログラムは存在しない
集合は顧客と継承という 2 種類のクラス間関係で構造化される
オブジェクト指向によるソフトウェア構築とは,抽象データ型の(その部分
的な実装も含む)構造化された集合として,ソフトウェアシステムを構築す
ることである.
定義2
オブジェクト指向によるソフトウェア構築とは,(システムが保証しようと
する機能や機能群ではなく)操作するオブジェクトの型から導かれるモ
ジュールを基本に,すべてのソフトウェアシステムのアーキテクチャを構築
するソフトウェア開発手法である.
定義1
31. 2011/2/28 オブジェクト指向プログラミング入門 4 31
暗黙性について
ADT による仕様記述
x: POINT → REAL
y: POINT → REAL
Pascal のような伝統的なプログラミング言語による記述
type POINT = record x, y: real end
重大な違い
Pascal の形式は閉じられていて明示的である.すなわ
ち, POINT オブジェクトは 2 つのフィールドから構成されてい
て,それ以外ではないことが示されている.
Pascal の宣言は直積としての POINT の定義
ADT の関数宣言は,点の x と y について問い合わせることがで
きることを示しているが,その他の問合せについても除外して
いない
ADT では,暗黙的に POINT の特徴を示している
32. 2011/2/28 オブジェクト指向プログラミング入門 4 32
仕様 vs. 設計
ソフトウェア開発の段階
初期の活動:仕様記述,分析
後の段階:設計や実装など
仕様記述はどこで終わり,設計がどこで始まるのか?
設計から実装への移行は,単に 1 つの明示的な形式からもう 1
つの明示的な形式に移動することである.
設計の形式:抽象的で数学的概念に近い
実装の形式:具体的でコンピュータに近い
オブジェクト技術はほとんど設計と実装の区別を取り去るもの
である
仕様記述から設計へと進むとは,個々の抽象を上で示したように,例えば単
純な問合せを直積として表していくということである.
定義:分析(仕様記述)から設計への移行
33. 2011/2/28 オブジェクト指向プログラミング入門 4 33
仕様記述は完了したか?
ADT の仕様記述が完了したかどうかを判定する手法
は存在しない
完全性( completeness )という概念を取り入れる
特定の ADT に対する 1 つまたは複数の関数を含む良形( well-formed )の式
を f(x1,…, xn) とする.すべての xi が(再帰的に)正しく,同時に,それらの
値があれば, f の事前条件を満たす場合にのみ,この式は正しい.
定義:正しい ADT 式
その理論の公理によって任意の良形の式 e について,次の問題を解決できる
場合にのみ,型 T についての ADT 仕様記述は十分に完全であるとする.
S1 ● e が正しいかどうかを判定する
S2 ● e が問合せ式であり, S1 において正しいことが示されている場合に,
T 型の
任意の値を含まない形式で e の値を表す
定義:十分な完全性
34. 2011/2/28 オブジェクト指向プログラミング入門 4 34
仕様記述は完了したか?
( contd. )
ちなみに無矛盾性に似た概念として健全性( soundness )とい
うのがある...
ある公理系が健全であるとは,それによって証明された命題は
必ず真であることを意味する
完全性と逆の関係
真ならば必ず証明できる
ここら辺の話題を深く理解するには「計算論理」を学んでくだ
さい
エルブラン定理とかゲーデルの不完全性定理とか面白い話題が
いっぱいあります...
任意の良形の問合せ式 e について,その公理群が e に対して多くとも 1 つの
値を導くことができる場合にのみ, ADT 仕様記述は無矛盾である.
定義: ADT の無矛盾性
35. 2011/2/28 オブジェクト指向プログラミング入門 4 35
十分な完全性を証明する
任意の ADT 仕様記述における一般的な手続
きは存在しないが,特定の仕様については個
別に証明できることもある
STACK の ADT 仕様記述を例に:
任意のスタック表現 e について以下を証明すれば
よい
e が正しいかどうかを判定できる
上記において e が正しく,その最も外側の関数が item
か empty の場合, STACK[G] 型の値や STACK の仕様記
述の関数を全く参照せずに, BOOLEAN と G の値だけ
を使って e の値を表現できる
e の構造に関する帰納法で証明可能