2013/07/17 このエントリーをはてなブックマークに追加 はてなブックマーク - 【JavaBeans】BeanとDTOとEntityとVOとFormの違いって何?

【JavaBeans】BeanとDTOとEntityとVOとFormの違いって何?

カテゴリ: , , , , ,






色んなシステムに携わっていると、様々なJavaのクラス名に遭遇する。






○○Beanとか ○○DTOとか ○○Entityとか ○○VOとか ○○Form







ここらへんって


「MVCのModelのデータ部分にあたるって意味で同じだし」

とか

「ゲッター/セッターがあるクラスで意味的に一緒じゃない?なんで色々名前つけてんの?」

って思いませんか?



ってことで、今回はそれぞれの定義を改めて考えてみようと思う。








・Bean




総称はBean。あえて言うならJavaBeansの略。


Javaの初心者でも知っている。
あまりに有名すぎるが、Oracleのサイトのガイドを見ながらパクってまとめてみた。




・Sun Microsystems社のJavaBeans仕様に準拠した再使用可能なソフトウェア・コンポーネント。

・最低限、クラスにはプロパティが必要。

・プロパティはメソッドを使用する他のJavaクラスに公開される。

・ただし、アクセス修飾子はprivateとし、次のメソッドをコールする必要がある。

set PropertyName
get PropertyName
※PropertyNameは、プロパティの名前。

プロパティはBeanクラスに格納され、メソッドを介してこれらの属性を取り出し、設定する。






JavaBeansを使用する3つの利点



JavaBeansには、アプリケーションを素早く効率的に作成できる大きな利点がある。





1.標準コンポーネント・モデルとしての認知度が高い



JavaBeansはSun Microsystems社のオープン標準であり、誰でも自分の製品に
JavaBeansの設計パターンでクラスを実装して自分のアプリケーションに組み込むことが出来る。
従って、Java開発および配布環境を生産する複数のハードウェアおよび
ソフトウェア・ベンダーからの幅広いサポートが可能になる。


つまり、誰でも知ってるから、誰でも直しやすいし、誰でもサポートしやすいよってこと。






2.プラットフォームに依存しない

JavaBeansはプラットフォームに依存しないので、
一式のJavaBeansを作成し、コードを変更せずに異種環境に配布可能。
また、異なるハードウェアやOSの互換性の問題を気にすることなく、
サード・パーティ製のJavaBeansをアプリケーションで再使用出来る。


同じ、設計ルール、デザインパターンなので、ハードやOS、
利用することが出来るってこと。






3.サード・パーティ製コンポーネントに対応しやすい

入手可能な多数のサード・パーティ製JavaBeansを使用して、アプリケーションに組み込み、
カスタマイズできます。 既存のコンポーネントを組み込み、カスタマイズすることで、開発時間を大幅に短縮出来る。


サード・パーティ製コンポーネントとして利用のしやすさが向上するし、
内容が理解しやすい分、開発効率が上がるって話。


「再利用性が高い」と言われる理由は上記の3つのメリットが大きく関わっているわけだ。





(参考元URL http://otndnld.oracle.co.jp/tech/java/htdocs/java_roadmap/javabean/listing.htm)



(しかし、Sun Microsystemsの頃のURLが全て
OracleのJavaのサイトのトップにリダイレクトされる仕様はどうにかならんかね。。
古い情報が全然見つからないし、よく困る。)






*2017/4/27追記*
aoetkさんが素晴らしい記事を書いていたのでリンクしておく。
getterやsetter以外のメソッドをJavaBeansのアクセッサにする




・ DTO





総称はData Transfer Object。データを転送するオブジェクト。
データは最終的にはDB処理に利用されることが前提とされている。




DTOってなに?




DTOは、

「プロセスまたはネットワークの境界を越えて転送する必要がある
集計データの集合に対する単純なオブジェクト」


である。


ビジネスロジックが含まれず、内部的な整合性チェックや、基本的な検証などの活動にその挙動を制限する必要がある。
DTOは、これらのメソッドを実装することの結果として、


新たなクラスに依存することがないように注意が必要である。



簡単に言うと、Beanとしてのゲッター/セッター等のメソッドと、
それ以外に実装するにしてもvalidtaionチェックメソッドぐらいにするようにすべし、ということ。
(個人的にはシンプルなゲッター/セッターのみのクラスの方が良いと思うが)



・値の保持の仕方について


ジェネリックコレクションを使用するか、明示的なgetterメソッドと
setterメソッドを持つカスタムオブジェクトを作成する。

つまり、MapかListを使って値を格納するか、各プロパティをゲッター/セッター
管理するかの2パターンがあるということ。





ジェネリックコレクションでは、アプリケーション全体を通して
データ転送目的に合わせて必要とする独自のデータを保有するクラス設計ができるメリットがある。
さらに、コレクションクラス(例えば、単純な配列やハッシュマップ)は、
ほぼすべての言語ライブラリに組み込まれているので、
わざわざ新しいクラスをコーディングする必要がない。




DTOを利用することで発生する主な欠点は、
クライアントが位置インデックス(単純な配列の場合)、
または要素名(キー付きコレクションの場合)のいずれかによって
内部フィールドにアクセスしなければならないことである。


また、コレクションは、コンパイル時に検出できない微妙だが
致命的なコーディングエラーにつながる可能性がある。


DTOクラスを使い、データを移入する必要があるタイミングにおいて、ほとんどの場合、
DTO内のデータは、複数のドメインオブジェクトから導出される。
(例:金額情報、ユーザー情報、セッション情報などなど)
DTO自体はロジックを持たないので、ドメインオブジェクトからデータを抽出することは出来ない。



つまり、DTOは色んな場所から情報をかき集める必要があるんだけど、
DTO自体はDTOが必要とする情報(プロパティ)を集めてくるメソッドは持たないってこと。





なぜDTOは必要か


リモート呼び出し(DBからの取得など別端末やネットワークとの通信)をする際の問題点に起因する。


・リモートファサードなどのリモートインタフェースへの各呼び出しで実装すると高負荷になり、処理が重くなってしまう

・呼び出し頻度(コールの数)を削減する必要があり、呼び出し毎に多くのデータを転送する必要がある

・ドメイン(意味のかたまり)ごとの情報はプロパティの量が多く、処理や管理が煩雑になる




処理が重くなるし、必要な情報が分かりにくいんだよなー。ってこと。


DTOを使えば、必要な情報だけ格納できるし、処理効率も良くなるんじゃ、、、?っていう流れになるわけです。




解決策としてのDTO



リモート呼び出しのために必要とされるすべてのデータを保持するデータ転送オブジェクト(DTO)を作成する。


DTOに関連する以下2つのルールがある

1.接続を介して直列化(シリアライズ)される必要がある
(implements Serializableしろってことですね)


2.単一のパラメータとしてDTOを受け入れられるように、クライアントにDTOパラメータを返す形式に リモートメソッドのシグネチャを変更する
(つまり、サーバーサイドのreturn値を必要な情報を格納したDTOのクラスインスタンスとするということ。)


呼び出し側のアプリケーションがDTOを受け取り、ローカルオブジェクトとして格納した後、
アプリケーションはリモート呼び出しのオーバーヘッドを発生させることなく、
個々の手続きの一連のDTOへの呼び出しを行うことが可能。







マーティン・ファウラー(Martin Fowler)氏は、
エンタープライズアプリケーションアーキテクチャのパターンで、
このパターンを説明している。
通常、DTOはアセンブラDTO、任意のドメインオブジェクト間で
データを転送するためにサーバ側で使用されている。
(つまり、サーバーサイドのプログラミングでDTOは利用されるってこと)








リモート呼び出しでない場合も使用ケースはある(ローカル呼び出し)



・プレゼンテーション層とその下層のドメインモデル内のモデルの間に有意な不一致がある場合



特定のプレゼンテーションファサード/ドメインモデルの紐づけでは、プレゼンテーションのための
都合の良いインターフェースを提供するゲートウェイを用意することは理にかなっている。






プレゼンテーション層のモデルパターンにもあてはまるからだ。
ミスマッチを持つ画面のためやる価値があるといえる。


画面とドメインが異なる場合は、
画面でDTOの利用が必要と考えられるので、無駄にならない作業である。




また、マルチスレッドのアプリケーションにおいて、
DTOは、そのエリア内での同時実行制御の必要性を排除する。


このような独立した地域との間で通信する必要がある場合は、
情報を転送するためにメッセージとしてDTOを使用してメッセージキューを使用するなどの例もある。







セキュリティの考慮事項

・信頼できない情報の妥当性チェック



Webページからユーザ入力など信頼できないソースから得られたデータは、
DTOに配置される前にクレンジングを行い検証する必要がある。
それにより、DTOとの間の相互作用が簡素化され、比較的安全なDTOにデータを検討することが可能。




・ユーザー権限の考慮

DTOを受けるプロセスと関連付けられているユーザーの
セキュリティ資格情報を考慮することも重要。

DTOは、多くの場合、多数の異なるソースから組み立てられる大量の情報を含んでいる。


すべてのユーザーに、DTOに含まれるすべての情報にアクセスする権限を与えていませんか?


ユーザーが許可されていることを確認する最良の方法は、
ユーザーのセキュリティ権限によって許可されている範囲の情報をDTOに格納すること。


しかし、セキュリティ部分のロジックをDTOに持たせることはやめよう。
各DTOにセキュリティのロジックの実装が必要になってしまうから。




(参考にしたURL
http://msdn.microsoft.com/en-us/library/ms978717.aspx
http://martinfowler.com/bliki/ValueObject.html
http://martinfowler.com/bliki/LocalDTO.html
http://martinfowler.com/eaaCatalog/dataTransferObject.html
)


余談だが、
サン・コミュニティの多くの人(Javaにかかわってる人たち)は、このパターンのために用語 "ValueObject"を使用する。
というかJ2EEパターンでは昔はDTOって呼ばずVOって呼び方がされていたらしい。 そのせいか、VOとDTOを混同してる人も多い気がする・・・・。





ってことで、次はVO(ValueObject)について説明する。




・ VO


2022/7/31 追記。
最近はkumagiさんの素晴らしい記事があるので、
僕の書いた文章よりこちらを参照した方が良さそう。 https://kumagi.hatenablog.com/entry/value-object
僕の解釈が曖昧なところが多々あった。なので読み飛ばしてもらって構わないです。

総称はValueObject。
アジャイル開発宣言とかXP(エクストリームプログラミング)で有名なマーティン・ファウラー
によると「お金」や「幅」といった小さなオブジェクトを指すらしい。


オブジェクトとしての塊というより、プロパティを基準にしたクラスとのこと。


DDD(domain driven design:ドメイン駆動設計)のデザインパターンとされる。
多分、起源はマーティン・ファウラーだと思う。


VOは値が不変であるべきとされている。
なんというか、値という概念自体がVOのインスタンスになるというイメージ。
例えば日付クラスもVOにしやすい。
業務日付、最終営業日、翌月の最初の営業日などを1つのインスタンスで
使いまわすとものすごいわかりにくい。



これに対して、VOのデザインパターンにして業務日付クラス、最終営業日クラス、翌月の最初の営業日クラスなどを作ると
可読性が上がり、意味合いがはっきりしてくる。
1つのインスタンスで使いまわすとものすごいわかりにくいというのは、可変であると同時に変数名が変わらないためである。


Date businessDate = new Date();


とかインスタンスを生成しようものなら、businessDateが使いまわされ、


「businessDateって結局ナンナノ???」



って状態になってしまう。


それを解決するのがVOのデザインパターン。


思想としては
・値の設定はコンストラクタ(インスタンスの生成時)のみ
・セッターメソッドは実装しない
・値は不変とする

だから、ゲッター/セッターを利用してVOと称するクラスを作っている場合、根本的に間違ってる。



しっかり勉強するなら、DDDの本か、
マーティン・ファウラーの「Patterns of Enterprise Application Architecture」を読む必要があるだろう。






(参考にしたURL http://masuda220.jugem.jp/?eid=308
↑かなり分かりやすかった。



・ Entity





総称はそのままEntity。訳すなら実体。永続化可能なJavaオブジェクト。
データストレージの単位の実体。
つまり、DBのテーブル単位として扱われることが多い。
DBのテーブル単位でEntityを利用する場合、必ず主キーを所有している必要がある。



EJBの登場とともに出来たJ2EEデザインパターンのようである。
EJBの1.xと2.xまではEntityBeanとして、EJB3.xからは
JPAという別APIライブラリとなった。




主に利用されるのは前述のとおりDBのテーブルのカラムに対してゲッター/セッターを用意する方式だと思うが、
JPAではXMLやLDAPなんかも対応しているとのこと。
JPAになり、大きく変わったのは、Entityアノテーションによりクラスが生成出来るようになったこと。
これにより、生産効率が上がっている。


Entityの1インスタンスがDBのレコードの1行に相当する、というイメージで良いと思う。






(参考にしたURL http://public.dhe.ibm.com/software/dw/jp/websphere/was/was61_ejb3fep_ws/ejb3_03java_persistence_api.pdf





・ Form





総称はそのままForm。StrutsやSpringなどで多くのクラス存在する。
起源はやっぱりStrutsだろうな。
画面の入力フォームという意味合いが強い。




しかし、FWのクラスでは色々できちゃうので、Validateの処理とか含まれちゃったり。
ModelとControllerが完全に分離しない実装もできちゃうのです。

ActionForm、DynaActionForm、DynaValidatorFormとか)




















BeanとDTOとEntityとVOとFormの違いはかなりあることが分かったと思う。



まず、Javaの基本的な考え方としてJavaBeans、つまりBeanが存在する。
そのくくりの中で(JavaBeansのデザインパターンの中で)、DTO、Entity、Formが存在する。
VOについては全く別物と考えて良いと思う。


今回のを頑張って図にまとめてみた(笑)









それぞれ、デザインパターンの用途や目的によって使い分けることによって、
理解しやすく、理に適ったシステムを作っていくことが出来るだろう。





※匿名さんのご指摘により、「MVCのモデルにあたる」→「MVCのモデルのデータ部分にあたる」に表現を修正しました。(2013/11/23)



10 件のコメント:

匿名 さんのコメント...

非常にわかりやすかったです!
ありがとうございました。

yy_yank さんのコメント...

>匿名さん

ありがとうございます!
お役に立てた用で嬉しいです!
また分かりやすかったと言ってもらえるように頑張ります!

匿名 さんのコメント...

Modelにあたるなら、ビジネスロジックが必要では?

yy_yank(やんく) さんのコメント...

>匿名さん

あー、言われてみれば確かにそうですね。今回はビジネスロジックは除くデータ部分の扱いについて
考えてみましたので、エントリの一部を修正しました。
ご指摘ありがとうございます!

匿名 さんのコメント...

今でもDTOの意味で「VO」を使っているケースが多いように思えますねー。というか、むしろそっちの意味しか知らない人の方が多いというか・・・。
現場で「VO」と言うとあらぬ誤解を生むので、「値(あたい)オブジェクト」(日本語にしただけですが・・・)などと言う様にしています。

yy_yank(やんく) さんのコメント...

>匿名さん
確かに、プロジェクトやインターネット上でもDTOとVOが混同されているのはよく目にします。
マーティンファウラーいわく、古くは(といってもJ2EEの頃ですが)VOを現在のDTOの意味で使っていたんですよね。
http://martinfowler.com/bliki/ValueObject.html

多分その名残があったりするんだ思います!

匿名 さんのコメント...

御大達も整理しれきないまま言葉をどんどん生み出しちゃってる感じが・・

師子乃 さんのコメント...

たしかに、色々あってややこしいです。
よくよく勉強が必要ですね。

匿名 さんのコメント...

BeanやEntity等の違いを調べていてこのサイトに行きつきました。
大変参考になります。
私はStrutsで開発しており、画面から入力されたデータはFormクラスでデータを保持するのが望ましいというのが分かりました。
そこで質問なのですが、Formクラスで保持した入力データをDBへ保存する場合は新たにEntityクラスを作成し、Formクラスで保持しているデータをEntityクラスに移し、EntityクラスからDBへ保存をするべきなのでしょうか。
仮にFormクラスで保持するデータを加工編集しない場合、冗長な処理になってしまう気がします。
Formクラスのデータを加工編集するかどうかで考えが変わったりするのでしょうか。

yy_yank(やんく) さんのコメント...

匿名さん

>そこで質問なのですが、Formクラスで保持した入力データをDBへ保存する場合は新たにEntityクラスを作成し、Formクラスで保持しているデータをEntityクラスに移し、EntityクラスからDBへ保存をするべきなのでしょうか。


基本的には、FormからEntityへの変換が必要になると思います。

>仮にFormクラスで保持するデータを加工編集しない場合、冗長な処理になってしまう気がします。
Formクラスのデータを加工編集するかどうかで考えが変わったりするのでしょうか。

例えば、Formの一部のデータだけを利用して、データの加工や複雑なロジックなど無しで
単純にUPDATEをかける場合などは冗長に感じてしまうと思います。
しかし、仕様変更や追加機能の実装の容易さを考慮すると変換処理を1つ噛ませておくような実装にしておく方が良いように思います。

使用しているフレームワークやパッケージ構成などによっても方式が変わって来るものだと思いますが、
Formというのはrequestに依存したものなので、典型的なweb3層アーキテクチャでいうところの、プレゼンテーション層に使用を収めておくのが望ましいです。

コメントを投稿

GA