オブジェクト指向設計の原則2

オブジェクト指向設計の原則 2
リスコフ代替の原則&依存関係逆転の原則&インターフェイス分離の原則
1
オブジェクト指向設計の原則2
2
3
前回の復習...............................................................................................................................2
4
リスコフ代替の原則(LSP: Liskov Substitution Principle)...................................................3
5
依存関係逆転の原則(DIP: Dependency Inversion Principle) ...............................................5
6
インターフェイス分離の原則(ISP:Interface Segregation Principle) ...................................6
7
1
オブジェクト指向設計の原則 2
リスコフ代替の原則&依存関係逆転の原則&インターフェイス分離の原則
8
9
前回の復習
10
11
12
単一責務の原則(SRP: Single Responsibility Principle)
・クラスを変更する理由を一つにする
13
14
15
開放/閉鎖の原則(OCP: Open-Closed Principle)
・モジュール自体を変更することなく、モジュールの環境を変更できなければならない
2
オブジェクト指向設計の原則 2
リスコフ代替の原則&依存関係逆転の原則&インターフェイス分離の原則
16
17
リスコフ代替の原則(LSP: Liskov Substitution Principle)
18
19
簡単にいうとどんな原則?
20
21
派生クラスは基本クラスの代わりとして動作できなければならない
22
23
具体的にいうと
24
25
基本クラス(抽象クラスまたはインターフェイス)と同じように、それを継承した派生ク
26
ラスも同じように使用できなければならない。例えば図1のような社員クラスと小切手ク
27
ラスがあるとします。社員クラスを小切手クラスに渡すと小切手での支払いが行われます。
28
29
図.1
30
31
もう少し細かく見てみると、Employee 抽象クラスがあり、派生クラスに SalariedEmployee
32
クラスと HourlyEmployee クラスと VolunteerEmployee クラスがあります。しかし、この
33
実装方法にはおかしいところがあります。それは VolunteerEmployee クラスです。ボラン
34
ティアには給料が支払われません。それならば VolunteerEmployee クラスの calcPay メソ
3
オブジェクト指向設計の原則 2
リスコフ代替の原則&依存関係逆転の原則&インターフェイス分離の原則
35
ッドの実装の戻り値を 0 にすれば問題ないです。それもどうでしょうか。calcPay メソッド
36
の実装は給料の支払い義務があるということになります。そうすると、給料 0 の支払い小
37
切手を郵送してしまう可能性が発生してしまいます。
38
ならばボランティアだけ支払い小切手を郵送しないように Check クラスに処理を加えれば
39
いいのではないか?これがまさに「リスコフ代替の原則」に反しているところです。派生
40
クラスによって処理を加えなければならない。Check クラスは Employee クラスだけを知
41
っていればいいはずが、Employee クラスの派生クラスまで知っておかなくてはいけない状
42
態が発生してしまいます。
43
このようなことが繰り返されると Employee クラスの実装するクラスの量が増えれば増え
44
るほど Check クラスの実装が大変になります。
45
46
それでは VolunteerEmployee クラスはどうすればいいのか?ボランティアは従業員ではあ
47
りません。つまり Employee クラスから派生するべきではありません。また calcPay メソ
48
ッドも持たせてはいけません。
49
50
自分はこのように修正してみました。
51
4
オブジェクト指向設計の原則 2
リスコフ代替の原則&依存関係逆転の原則&インターフェイス分離の原則
52
53
依存関係逆転の原則(DIP: Dependency Inversion Principle)
54
55
簡単にいうとどんな原則?
56
57
メソッドを使う側(クライアント)がメソッドを使われる(サプライヤ)側に依存してはならな
58
い。
59
抽象化は詳細に依存してはならない。詳細は抽象化に依存しなければならない
60
61
具体的にいうと
62
一時的な具象クラスに依存してはならない。変数の参照を抽象クラスにします。メソッド
63
を呼び出す場合、それを抽象メソッドにします。抽象クラスやインターフェイスが変更さ
64
れることは具象クラスよりはるかに少ないです。そのため具象クラスに依存するより抽象
65
クラスやインターフェイスに依存したほうがシステムは安定します。
66
67
例えば Propel の Connection を取得するソースコードを書く場合、クライアントは mysql
68
の Connection を取得するというコードは書かないです。
69
70
$con = Propel::getConnection(); //return Connection interface
71
$con->begin();
72
//SQL
73
$con->commit();
74
75
クライアントは mysql のコネクションという詳細には依存せず、Connection インターフェ
76
イスに依存します。サプライヤが Connection インターフェイスを implements して実装し
77
ます。クライアントは Connection インターフェイスに依存するおかげで、新しい DB が増
78
えようと一切変更することはありません。なぜなら詳細に依存していないからです。
79
依存関係逆転の原則に違反すると自動的に開放閉鎖の原則にも違反します。
5
オブジェクト指向設計の原則 2
リスコフ代替の原則&依存関係逆転の原則&インターフェイス分離の原則
80
81
インターフェイス分離の原則(ISP:Interface Segregation Principle)
82
83
簡単にいうとどんな原則?
84
85
使用しないメソッドに依存してはならない
86
87
具体的にいうと
88
89
単一責務の原則のインターフェイスバージョン。
6