添付ファイルの追加

ログイン済のユーザのみが添付ファイルをアップロード出来ます。

添付ファイル一覧

Kind Attachment Name Size Version Date Modified Author Change note
png
custocompany1.png 3.3 kB 1 25-6-2011 03:28 ytp
png
custocompany2.png 4.1 kB 1 25-6-2011 03:28 ytp
png
name.png 8.2 kB 4 31-12-2011 21:46 ytp
png
name2.png 8.3 kB 3 31-12-2011 21:43 ytp
png
supplyer.png 3.4 kB 1 25-6-2011 03:28 ytp

This page (revision-22) was last changed on 25-7-2014 20:50 by ytp

This page was created on 23-5-2011 01:03 by ytp

Only authorized users are allowed to rename pages.

Only authorized users are allowed to delete pages.

Difference between version and

At line 4 changed one line
!「privateメソッドに渡すパラメータをひとかたまり(データ構造)とするクラスを見逃している。」
*privateメソッドに渡すパラメータをひとかたまり(データ構造)とするクラスを見逃している
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 58 changed one line
パラメータの無い、つまり__共通関数ですらないprivateメソッド__がなぜ必要なのでしょうか? 彼らの答えは「可読性をあげるため長いコードを分割するんだ。」なのですが、私に言わせると「ちゃんちゃら可笑しいw」です。\\
パラメータの無い、つまり__共通関数ですらないprivateメソッド__がなぜ必要なのでしょうか? 彼らの答えは「可読性をあげるため長いコードを分割するんだ。」なのですが、これは全くの誤りであると私は考えます。\\
At line 110 changed one line
正しいクラスを定義した結果、それでもメソッドの記述が長くなる場合、例えば属性が100個ぐらいあって一つの処理が長くなる場合、それはそれで正しいのです。意味も無く分割する必要は無いというのが私の考えです。
正しいクラスを定義した結果それでもメソッドの記述が長くなる場合、例えば属性が100個ぐらいあって一つの処理が長くなる場合、それはそれで正しいのです。意味も無く分割する必要は無いというのが私の考えです。
At line 115 changed one line
フィールド(属性)の周りをメソッドが取り巻いている形が見えますが、これは裏返すと、「フィールドを隠蔽するためにメソッドが口を開けている」ということです。つまり公開されないメソッドはこの原則に反するのです。__privateによって隠蔽するべきなのはフィールドであってメソッドではない__という原則がこの図からも解ります。\\
フィールド(属性)の周りをメソッドが取り巻いている形が見えますが、これは裏返すと、
*フィールドを隠蔽するためにメソッドが口を開けている(公開されている)
ということです。つまり公開されないメソッドはこの原則に反するのです。
*privateによって隠蔽すべきなのはフィールド(属性)であってメソッドではない
という原則がこの図からも解ります。\\
At line 141 changed one line
[関数とユーティリティクラスは禁止]でも書きましたが、このようなユーティリティクラス(インスタンス変数にもクラス変数にもアクセスしないメソッド群)はそもそもオブジェクト指向の原則である「データ構造と関数の一体化」を崩してしまいます。その結果どういう事が起きるかを考えてみます。\\
[関数とユーティリティクラスは禁止]でも書きましたが、このようなユーティリティクラス(インスタンス変数にもクラス変数にもアクセスしないメソッド群)はそもそもオブジェクト指向の原則である
*データ構造と関数の一体化
を崩してしまいます。その結果どういう事が起きるかを考えてみます。\\
At line 146 changed 2 lines
private String yuubinBangou = "";
private String jyuusho = "";
private String yuubinBangou = ""; // 郵便番号
private String jyuusho = ""; // 住所
At line 156 changed 3 lines
StringUtility#getFullName()メソッドの機能は、「1つめのパラメータと2つめのパラメータを2個のスペースを挟んで連結する」というものです。上記のように、「事務所クラスの宛先を返すメソッド」にこの機能がたまたま使えたとすれば使われる可能性を排除できません。\\
この時、システムを国際化対応する必要がもしも出てきて、「担当者ミドルネーム」「代表者ミドルネーム」という属性が追加になったとします。そして、「氏名を返すメソッドは全て『姓 ミドルネーム 名』とする(間のスペースは1つずつ)」という要件に替わったとします。\\
この場合の変更箇所はStringUtility.getFullName()メソッドのみではなく、それを呼び出している全メソッドが対象となります(当然ですが)。その際、「従業員クラスの宛先を返すメソッド」も該当しますが、事務所クラスは「ミドルネーム」を持たないため破綻してしまいます。別の関数を新たに作る必要が出てきます。\\
StringUtility#getFullName()メソッドの機能は、「1つめのパラメータと2つめのパラメータを2個のスペースを挟んで連結する」というものです。上記のように、「事務所クラスの宛先を返すメソッド」にこの機能がたまたま使えたとすれば使われてしまう可能性を排除できません。\\
この時、システムを国際化対応する必要がもしも出てきて、
*担当者ミドルネーム
*代表者ミドルネーム
という属性が追加になったとします。そして、
*氏名を返すメソッドは全て『姓 ミドルネーム 名』とする(間のスペースは1つずつ)
という要件に替わったとします。\\
この場合の変更箇所はStringUtility.getFullName()メソッドのみではなく、それを呼び出している全メソッドが対象となります(当然ですが)。その際、「従業員クラスの宛先を返すメソッド」も該当しますが、事務所クラスは「ミドルネーム」を持たないため破綻してしまいます。別の関数を新たに作る必要が出て来るのです。高い保守性とこれでは言えません。\\
At line 160 changed 4 lines
一方で、「氏名クラス」を利用している場合はどうでしょう?\\
氏名クラスを利用する場合、そのデータは「姓」と「名」として使うことでしょう。「郵便番号」と「住所」を無理矢理入れようと思えば入れられますが、上記のユーティリティクラスの使われ方ほどの可能性はありません。 なぜならば、ユーティリティクラスの目的は「処理」、つまり「1つめのパラメータと2つめのパラメータを2個のスペースを挟んで連結する」という機能を提供することですが、氏名クラスの目的は__氏名となるデータを保持すること__だからです。誤用の可能性は低いでしょう。\\
ひとかたまりとなるデータ構造をクラスに閉じ込め、そのデータに関する処理も併せてその中に閉じ込めてしまうことで修正箇所を最小限にしようというオブジェクト指向の目的がこの例からも解ります。
[{Image src='name2.png'}]
一方で、「氏名クラス」を利用している場合はどうでしょうか。\\
氏名クラスを利用する場合、そのデータは「姓」と「名」として使うことでしょう。「郵便番号」と「住所」を無理矢理入れようと思えば入れられますが、上記のユーティリティクラスの使われ方ほどの可能性はありません。\\
なぜならば、ユーティリティクラスの目的は「処理」つまり
*1つめのパラメータと2つめのパラメータを2個のスペースを挟んで連結する
という__機能を提供すること__ですが、氏名クラスの目的は、
*氏名を構成する属性(データ構造)を保持すること
だからです。誤用の可能性は低いでしょう。\\
[name2.png]\\
氏名クラスを利用している場合、__氏名を返す()__メソッドを呼び出している側の修正は必要ありません。このことがシステムの保守性をいかに高くするかを是非理解して下さい。\\
ひとかたまりとなるデータ構造をクラスに閉じ込め、そのデータに関する処理も併せてその中に閉じ込めてしまうことで修正箇所を最小限にしようというオブジェクト指向の目的がこの例からも解ります。\\
At line 170 changed one line
!再帰処理
!!再帰処理
At line 201 changed one line
!汎用的なデータ構造を持つクラスを継承せずに利用する
!!汎用的なデータ構造を持つクラスを継承せずに利用する
At line 232 changed one line
この場合のprivateメソッドは、汎用的なデータ構造を持つクラスを継承するならば必要なくなります。上の例ではArrayListクラスです。ですが、汎用的に出来ているクラスの継承においては、そのクラスのデータ構造を熟知していないと思わぬ副作用に出くわすデメリットもあるため、privateメソッド利用とのデメリットをよく検討した上で選ぶようにしてください。\\
この場合のprivateメソッドは、汎用的なデータ構造を持つクラスを継承するならば必要なくなります。上の例ではArrayListクラスです。ですが、汎用的に出来ているクラスの継承においては、そのクラスのデータ構造を熟知していないと思わぬ副作用に出くわすデメリットもあるため、privateメソッド利用とのデメリットをよく検討した上で選ぶようにして下さい。\\
At line 271 added 6 lines
!!まとめ
*privateメソッドを作っていけない
*ただし以下は例外
**再帰処理
**汎用的なデータ構造を持つクラスを継承せずに利用する場合
At line 238 changed one line
オブジェクト指向の出発点は「1ヶ所直せば皆直る」です。難しいことは置いておいても、これを目指して皆さんも設計・実装してみてください。そうすれば、オブジェクト指向の核心がきっと見えてきます。\\
オブジェクト指向の出発点は「1ヶ所直せば皆直る」です。難しいことは置いておいても、これを目指して皆さんも設計・実装してみて下さい。そうすれば、オブジェクト指向の核心がきっと見えてきます。\\
\\
次: [どのメソッドをどのクラスで実装すべきか]
Version Date Modified Size Author Changes ... Change note
22 25-7-2014 20:50 7.789 kB ytp to previous
21 31-12-2011 21:42 7.791 kB ytp to previous | to last
« This page (revision-22) was last changed on 25-7-2014 20:50 by ytp