At line 9 changed 2 lines |
[{Image src='custocompany1.png'}] |
「担当者姓」と「担当者名」という属性がこのクラスの中にはあります。そしてこの二つの値を使った「担当者氏名を返す」メソッドを作ってみます。姓と名の間にスペースを挟んで返す仕様だとすると、コードは次のようになるでしょう。 |
[custocompany1.png] |
*担当者姓 |
*担当者名 |
という属性がこのクラスの中にはあります。そしてこの二つの値を使った |
*担当者氏名を返すメソッド |
を作ってみます。姓と名の間にスペースを挟んで返す仕様だとすると、コードは次のようになるでしょう。 |
At line 19 changed 2 lines |
次に、このクラスが仕様変更となり、「代表者姓」と「代表者名」という属性が追加されたとします。「代表者氏名を返す」というメソッドもこの時必要になったとすると、以下のようなコードを追加することでしょう。 |
[{Image src='custocompany2.png'}] |
次に、このクラスが仕様変更となり、 |
*代表者姓 |
*代表者名 |
という属性が追加されたとします。\\ |
[custocompany2.png]\\ |
*代表者氏名を返すメソッド |
もこの時必要になったとすると、以下のようなコードを追加することでしょう。 |
At line 29 changed one line |
そして次に、「いずれの氏名を返す時も、姓と名の間のスペースを2つに替えて欲しい。」という要望が挙がったとします。よく見てみると上記二つのメソッドは非常に良く似ています。「スペースを挟んで姓と名を連結する」という仕様だからです。こういう時、privateメソッドを作っておくと変更が1ヶ所で済んだはずです。次のようなコードです。 |
そして次に、 |
*いずれの氏名を返す時も、姓と名の間のスペースを2つに替えて欲しい |
という要望が挙がったとします。よく見てみると上記二つのメソッドは非常に良く似ています。「スペースを挟んで姓と名を連結する」という仕様だからです。こういう時、privateメソッドを作っておくと変更が1ヶ所で済んだはずです。次のようなコードです。 |
At line 47 changed 2 lines |
[{Image src='supplyer.png'}] |
例えば「仕入れ先会社」クラスが別にあったとして、その属性にも「担当者姓」「担当者名」があったとしたらどうでしょう? そしてそのクラスにも「担当者氏名を返す」というメソッドが必要で、「姓と名の間にスペースを2つ挟む」という仕様だったら? そのクラスにも同じようなprivateメソッドが必要になってしまい、仕様変更への対応が1ヶ所というわけにいかなくなってしまいます。\\ |
例えば |
*仕入れ先会社クラス |
[supplyer.png]\\ |
が別にあったとして、その属性にも「担当者姓」「担当者名」があったとしたらどうでしょう? そしてそのクラスにも「担当者氏名を返す」というメソッドが必要で、「姓と名の間にスペースを2つ挟む」という仕様だったら? そのクラスにも同じようなprivateメソッドが必要になってしまい、仕様変更への対応が1ヶ所というわけにいかなくなってしまいます。\\ |
At line 51 changed 4 lines |
上記の例で解るように、__「privateメソッドを作りたくなった時はクラスを見逃している」__のです。\\ |
privateメソッドはクラス内の共通関数に当たるのですが、共通関数を作ろうとすれば、その関数に渡す__パラメータをそもそもまず共通化する必要があります__。そのパラメータをひとかたまり(データ構造)とするクラスを作るべきなのです。\\ |
この場合は、属性として「姓」と「名」を持つ「氏名クラス」を作るべきです。そしてそのクラスに__委譲__するのです。 |
[{Image src='name.png'}] |
上記の例で解るように、 |
!privateメソッドを作りたくなった時はクラスを見逃している |
のです。\\ |
privateメソッドはクラス内の共通関数に当たるのですが、共通関数を作ろうとすれば、その関数に渡す__パラメータをそもそもまず共通化する必要があります__。 |
!そのパラメータをひとかたまり(データ構造)とするクラスを作るべき |
なのです。\\ |
この場合は、属性として |
*姓 |
*名 |
を持つ「__氏名クラス__」を作るべきです。そしてそのクラスに__委譲__するのです。\\ |
[name.png] |
At line 115 changed one line |
フィールド(属性)の周りをメソッドが取り巻いている形が見えますが、これは裏返すと、「フィールドを隠蔽するためにメソッドが口を開けている」ということです。つまり公開されないメソッドはこの原則に反するのです。__privateによって隠蔽するべきなのはフィールドであってメソッドではない__という原則がこの図からも解ります。\\ |
フィールド(属性)の周りをメソッドが取り巻いている形が見えますが、これは裏返すと、 |
!フィールドを隠蔽するためにメソッドが口を開けている |
ということです。つまり公開されないメソッドはこの原則に反するのです。__privateによって隠蔽するべきなのはフィールドであってメソッドではない__という原則がこの図からも解ります。\\ |
At line 141 changed one line |
[関数とユーティリティクラスは禁止]でも書きましたが、このようなユーティリティクラス(インスタンス変数にもクラス変数にもアクセスしないメソッド群)はそもそもオブジェクト指向の原則である「データ構造と関数の一体化」を崩してしまいます。その結果どういう事が起きるかを考えてみます。\\ |
[関数とユーティリティクラスは禁止]でも書きましたが、このようなユーティリティクラス(インスタンス変数にもクラス変数にもアクセスしないメソッド群)はそもそもオブジェクト指向の原則である |
*データ構造と関数の一体化 |
を崩してしまいます。その結果どういう事が起きるかを考えてみます。\\ |
At line 157 changed one line |
この時、システムを国際化対応する必要がもしも出てきて、「担当者ミドルネーム」「代表者ミドルネーム」という属性が追加になったとします。そして、「氏名を返すメソッドは全て『姓 ミドルネーム 名』とする(間のスペースは1つずつ)」という要件に替わったとします。\\ |
この時、システムを国際化対応する必要がもしも出てきて、 |
*担当者ミドルネーム |
*代表者ミドルネーム |
という属性が追加になったとします。そして、 |
*氏名を返すメソッドは全て『姓 ミドルネーム 名』とする(間のスペースは1つずつ) |
という要件に替わったとします。\\ |
At line 161 changed 3 lines |
氏名クラスを利用する場合、そのデータは「姓」と「名」として使うことでしょう。「郵便番号」と「住所」を無理矢理入れようと思えば入れられますが、上記のユーティリティクラスの使われ方ほどの可能性はありません。 なぜならば、ユーティリティクラスの目的は「処理」、つまり「1つめのパラメータと2つめのパラメータを2個のスペースを挟んで連結する」という機能を提供することですが、氏名クラスの目的は__氏名となるデータを保持すること__だからです。誤用の可能性は低いでしょう。\\ |
ひとかたまりとなるデータ構造をクラスに閉じ込め、そのデータに関する処理も併せてその中に閉じ込めてしまうことで修正箇所を最小限にしようというオブジェクト指向の目的がこの例からも解ります。 |
[{Image src='name2.png'}] |
氏名クラスを利用する場合、そのデータは「姓」と「名」として使うことでしょう。「郵便番号」と「住所」を無理矢理入れようと思えば入れられますが、上記のユーティリティクラスの使われ方ほどの可能性はありません。\\ |
なぜならば、ユーティリティクラスの目的は「処理」、つまり |
*1つめのパラメータと2つめのパラメータを2個のスペースを挟んで連結する |
という機能を提供することですが、氏名クラスの目的は、 |
*氏名となるデータを保持すること |
だからです。誤用の可能性は低いでしょう。\\ |
\\ |
ひとかたまりとなるデータ構造をクラスに閉じ込め、そのデータに関する処理も併せてその中に閉じ込めてしまうことで修正箇所を最小限にしようというオブジェクト指向の目的がこの例からも解ります。\\ |
[name2.png] |