At line 2 changed one line |
「一個売りしているリンゴ」をシステムで扱う場合、どのような属性が必要になるかを考えてみます。\\ |
「__一個売りしているリンゴ__」をシステムで扱う場合、どのような属性が必要になるかを考えてみます。\\ |
At line 7 changed one line |
などが考えられます。それでは、「一山(ひとやま)売りしているリンゴ」はどうでしょうか? |
などが考えられます。それでは、「__一山(ひとやま)売りしているリンゴ__」はどうでしょうか? |
At line 13 changed 2 lines |
「一山売りしているリンゴ」では、「__一個あたりの売り値(平均の売り値)を返す__」というメソッドがすぐに思い浮かびます。\\ |
これらから解るように、「リンゴ」というクラスが設計段階、特に概念モデルで出てきても、それが一個なのか一山なのかを確定させないと正しいクラスとして設計できません。裏を返すと、同じリンゴであっても、それを扱う__単位が異なれば異なるクラス__として設計する必要があるということです。\\ |
「一山売りしているリンゴ」では、 |
*一個あたりの売り値(平均の売り値)を返す |
というメソッドがすぐに思い浮かびます。\\ |
これらから解るように、「リンゴ」というクラスが設計段階、特に分析クラス図で出てきても、 |
*それが一個なのか一山なのかを確定させないと正しいクラスとして設計できない |
のです。裏を返すと、同じリンゴであっても、 |
*それを扱う単位が異なれば異なるクラスになる |
ことを理解して設計する必要があるということです。\\ |
At line 17 changed one line |
前項で解るように、単位は非常に重要です。ここで言う単位というのは物理学で言うものではなく、業務を遂行する人たちがあるものをひとかたまりとして扱う大きさのことです。 |
前項で解るように、__単位は非常に重要__です。ここで言う単位は物理学で言うものではなく、__業務を遂行する人たちがあるものをひとかたまりとして扱う大きさ__のことです。 |
At line 27 added one line |
*一組織 |
At line 23 changed one line |
など色々ありますが、人間が何かをひとかたまりとして扱い、そのかたまりの種類が異なる場合には必ず単位が異なります。もちろん、非常に汎用的な「一個」という単位はあちこちで出てきますが、その場合は「何々一個」というように聞き分けて設計していけば問題ありません。\\ |
*一件 |
*一覧 |
など色々ありますが、人間が何かをひとかたまりとして扱い、そのかたまりの種類が異なる場合には必ず単位が異なります。もちろん、非常に汎用的な「一個」という単位はあちこちに出てきますが、その場合は「何々一個」というように聞き分けて設計していけば問題ありません。\\ |
At line 26 changed one line |
単位が異なると言っても、実際のシステムではどう考えればいいのでしょう? 答えは簡単で、__「『一件』と『一覧』は異なるクラスとして設計・実装する__」です。『件』と『覧』というふうに単位が異なるからです。\\ |
このページの見出しにある「リンゴ一個とリンゴ一山」を実際のシステムではどう考えればいいのでしょう? 答えは簡単で、 |
*『一件』と『一覧』は異なるクラスとして設計・実装する |
です。『一件』がリンゴ一個に相当し、『一覧』がリンゴ一山に相当します。\\ |
At line 31 changed one line |
顧客会社を一件のみ、つまり一会社として扱う時のクラスが「顧客会社一件クラス」です。__複数件として__、つまり顧客会社を一覧として扱う場合は「顧客会社一覧クラス」を作ります。一覧クラスは一件クラスを__内部で複数持つ__ように設計します。ほとんどのシステムにおいて両方必要です。\\ |
顧客会社を一件のみ、つまり一会社として扱う時のクラスが「顧客会社一件クラス」です。顧客会社を複数件で、つまり__一覧として扱う場合は「顧客会社一覧クラス」を作ります__。そして、__ |
*一覧クラスは一件クラスを内部で複数持つ |
ように設計します。ほとんどのシステムにおいてその両方が必要です。\\ |
At line 39 changed one line |
は、「一伝票」と「一明細」というように単位が異なるので別クラスとして定義します。明細は商品単位の情報を持っており、一伝票が複数の明細を持つ形です。 |
は、「一伝票」と「一明細」というように__単位が異なるので別クラスとして定義__します。伝票は、ある仕入れ先からのある日の入荷物全体を表現しています。伝票ヘッダとも言われます。明細は商品単位の情報を持っており、一伝票が複数の明細を持つ形です。 |
At line 43 removed one line |
#入荷伝票一件クラス |
At line 45 changed one line |
#入荷明細一件クラス |
#入荷伝票一件クラス |
At line 47 changed one line |
というように、それぞれ__一件__と__一覧__というように4つに分けて設計します。 |
#入荷明細一件クラス |
というように、それぞれ__一覧__と__一件__というように4つに分けて考えます。\\ |
At line 49 changed one line |
上記を見て、次のような設計でいいのではないかと気付いた人がいるかもしれません。伝票一件は明細一覧も請け負う形です。\\ |
これらのクラスの考え方は次の通りです。「一伝票」「一明細」というように異なる単位で呼ばれる物を見つけたら、それらをさらに「一覧」「一件」というふうに分けて考えます。 |
||モノ||一覧||一件 |
|入荷伝票(ヘッダ)| ○| ○ |
|入荷明細| ○| ○ |
|
\\ |
しかし上の図を見て、次のような設計でいいのではないかと気付いた人がいるかもしれません。__伝票一件が明細一覧も兼ねる形__です。\\ |
At line 51 changed one line |
ここだけの局面を見ればこの設計は正しいのですが、__伝票に依存しない明細一覧オブジェクト__を形成したい場合はうまくいきません。例えば、「伝票には関係せず、商品Aだけの明細一覧を表示する」というような要件に対応できないのです。そのため、伝票明細一覧クラスを必ず設計しておくようにします。\\ |
実は、 |
*入荷伝票クラスは入荷明細に対する一覧クラスを兼ねている |
のです。また、\\ |
*伝票に依存しない明細一覧オブジェクトを形成したい |
場合に上記ではうまくいきません。例えば、 |
*全ての伝票の中から商品Aだけの明細一覧を表示する |
というような要件に対応できないのです。入荷明細一覧クラスから参照できる入荷伝票が1つしかないことになり、 |
*入荷明細に商品Aを持つ複数の入荷伝票 |
という関係を表現できません。 |
このため、入荷伝票が入荷明細一覧クラスを兼ねる形で設計しておくようにします。\\ |
それとは別に、入荷伝票とは独立して入荷明細を一覧化するためのクラスも設計します。次のような形です。\\ |
[nyuuka8.png]\\ |
上記図のカージナリティに注意して下さい。\\ |
*入荷伝票一件クラスと入荷明細一件クラスは「1:1以上」 |
*入荷明細一覧クラスと入荷明細一件クラスは「1:0以上」 |
となります。入荷明細が1件も存在しない入荷伝票は許されません。一方で、「商品Aを持つ入荷明細」を検索した場合の結果が0件となることはあり得ます。 |
At line 54 changed one line |
永続装置としてRDBを使うことが実際の開発では日常的です。この時には、RDBテーブル一つに対して |
永続化装置としてRDBを使うことが実際の開発では日常的です。この時には、RDBテーブル一つに対して |
At line 58 changed 3 lines |
一レコードクラスは、前項で書いた一件クラスと同じ事です。物や結果の一件分がRDBテーブルの一レコードとして保存されます。\\ |
一テーブルクラスというのは少し解りにくいのですが、複数のレコードを扱う時に使います。複数のレコードというのは最大でそのテーブルの全件を持つことになり、言葉を換えると「一テーブル分」となります。これも前項で出てきた__一覧クラス__と同等です。\\ |
まとめると、 |
__一レコードクラスは前項で書いた一件クラスと同じ事__です。物や結果の一件分がRDBテーブルの一レコードとして保存されます。\\ |
一テーブルクラスというのは少し解りにくいのですが、複数のレコードを扱う時に使います。\\ |
*複数のレコードというのは最大でそのテーブルの全件を持つ |
ことになり、言葉を換えると |
*一テーブル分 |
となります。これも前項で出てきた__一覧クラス__と同等です。\\ |
関係をまとめると、 |
At line 63 changed one line |
となります。それぞれ何が違うかというと、一件クラスまたは一覧クラスのうちRDBに永続化する必要のあるものが、一レコードまたは一テーブルという__別の呼び方をされることがある__というだけです。永続化される必要の無いものは別名を持ちません。\\ |
となります。それぞれ何が違うかというと、一件クラスまたは一覧クラスのうちRDBに永続化する必要のあるものが一レコードまたは一テーブルという__別の呼び方をされることがある__というだけです。永続化される必要の無いものは別名では呼ばれません。\\ |
その上で、 |
*RDBから一件を取得する処理 |
*RDBから一覧を取得する処理 |
をそれぞれのクラスの中に実装します。次のような形です。 |
[nyuuka5.png]\\ |
この際、入荷伝票一件クラスのRDBから一件を取得する処理の中で、 |
*ひも付く複数件の入荷明細を取得する処理 |
も実装します。\\ |
At line 111 added 7 lines |
!!「複数件」が出てきたら一山クラスを作る |
RDBテーブルに限らず、__同じものを複数件扱う要件が出てきたならば「一山クラス(一覧クラス)」を必ず作ります__。これをせずに実装者任せにして何でもかんでもList(配列)に入れて実装してしまうと、いざ仕様変更が発生した時にあちこちを修正することになっていまいます。\\ |
Javaで実装する場合、ListやMapなどのコレクション(Collection)を一山クラスの内部で使います。\\ |
[{Image src='nyuuka6.png'}] |
明細の一覧を画面に表示する場合にある規則で並べたい、例えば商品順に並べたいような場合、一覧クラスの中でTreeMapクラスを使います(ただし入荷商品に重複がない前提)。そうすることで、ソート処理を別途用意する必要がなくなります。明細一覧というデータ構造とソート処理を分離することなく実装できるのです。\\ |
ソートに限らず、業務的な処理も一覧の中に実装します。例えば、「数量の一番多い明細を返す」という処理です。 |
[{Image src='nyuuka7.png'}] |
At line 66 changed one line |
__単位が異なるとクラスが異なる__という原則がこれで解ると思います。 |
!!まとめ |
*単位が換われば異なるクラスにする |
*複数件を扱う場合は一覧クラスを必ず作る |
|
!!コラム |
つい最近(2011年7月)ですが、「Grailsの開発においてリンゴ一山クラスを見逃していた結果、仕様変更の反映が数十ヶ所に及んでしまい工数をロスしました。」と、うちの若手が後悔していました。\\ |
__リンゴ一山クラスを作成せずに__何でもかんでもList(配列)に入れて実装してしまうと、似たような処理があちこちに作られる危険が高くなります。データと処理が分離されてしまうからです。\\ |
皆さんの開発現場において設計者がリンゴ一山クラスを見逃しているようならば、このページの内容を参考にして指摘してあげて下さい。\\ |