SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

IDDD本から理解するドメイン駆動設計

実践DDD本 第6章「値オブジェクト」~振る舞いを持つ不変オブジェクト~

IDDD本から理解するドメイン駆動設計 第6回

  • X ポスト
  • このエントリーをはてなブックマークに追加

値オブジェクトの特徴(2)

(3)概念的な統一体

 値オブジェクトは複数の属性(プロパティ)を保持しており、それらが相互に関係して値を説明することができます。例えば「通貨」という値オブジェクトの場合、円やドルといった「単位」と、その数量を表す「金額」を組み合わせることによって、適切な値を示すことができます。

 一つの属性値だけでは意味を持たず、それぞれが組み合わさることで適切な説明をできることを「概念的な統一体」と呼びます。通貨の場合、「100」や「円」だけでは意味を持ちませんが、「100円」であれば、完結した意味を持つ値となります。

(4)交換可能性

 値オブジェクトは(2)不変性の特徴を持つため、途中で値の変更を行うことができません。しかし、実際のプログラムでは値の変更を行いたいことがあると思います。そのようなときは、変更後の値を設定した新しいオブジェクトを生成し交換します。このように交換できることを「交換可能性」と呼びます。通貨の金額を変更したい場合、現在の値オブジェクトの値を元に新しい通貨オブジェクトを生成し交換します。

 なお、この手順が不便と感じて、エンティティを採用することがないように注意してください。前章でご紹介した通り、長期にわたって識別する必要があるオブジェクトだけがエンティティとなります。

(5)等価性

 値オブジェクト同士のインスタンスを比較する場合、等しいかどうかを判断する「等価性」の判定方法を提供する必要があります。エンティティでは「一意な識別子が同じか」で判定しましたが、値オブジェクトでは「各属性が持つすべての値が同じか」で判定します。

 つまり、属性の識別だけで同じかどうかを判断できる場合は、エンティティではなく値オブジェクトを使えないか検討してみてください。

(6)副作用のない振る舞い

 「副作用のない関数」とはエヴァンス氏がDDD本の「しなやかな設計」の部分で紹介しているパターンで、値オブジェクトの条件の一つです。副作用のない操作とは、「どのような状態で何回呼び出してもオブジェクトの状態が変わらない」操作を意味します。

 「副作用がない関数」とわかっていれば、そのメソッドを呼び出すときに、他への影響がないため、安心して実装やテストを書けます。4章で紹介したCQRSパターンでは、変更するコマンド(Command)と取得するクエリ(Query)を明確に分離していましたが、このクエリ部分が副作用のない関数となります。

 値オブジェクトは(2)の「不変」を満たすため、値を変更するメソッドは存在しません。そのため、副作用はさそうに思えます。しかし情報を取得するクエリでも、注意していないと副作用のある操作になる場合があります。例えば、三角形の面積を計算(縦と横を掛け2で割る)する関数で考えてましょう。

三角形の面積を計算する関数(副作用がある場合)
public int GetAreaSize(TriangleEntity entity) {
    entity.AreaSize = entity.Height * entity.Width / 2;
    return entity.AreaSize;
}

 メソッド名もGet~となっており、一見、副作用はなさそうにえます。しかし、このメソッドでは引数にエンティティを渡しており、そのAreaSizeプロパティの値を更新しています。そのため、このメソッドは「副作用がある」メソッドとえます。

 加えて、値オブジェクトでは可能な限り自分自身の情報だけを使って処理を行うことが望ましいとされています。このメソッドでは、引数のエンティティの情報を使って処理を行っています。これではエンティティの内部構造も理解する必要があるため複雑です。

 これらを改善した副作用のないコードを見てみましょう。

三角形の面積を計算する関数(副作用がない場合)
public int GetAreaSize(int height, int width) {
    int result = height * width / 2;
    return result;
}

 ここでは、引数としてエンティティを渡すことをやめています。エンティティのAreaSizeプロパティの値を変えなければ副作用がいともいえますが、呼び出し側に不安を感じさせることや、将来的に不変でなくなるリスクが高いこともあるため、エンティティのプロパティの値を渡すように変更しています。これで副作用のないメソッドとなりました。

 以上、値オブジェクトの特徴について紹介しました。

次のページ
複数コンテキストの結合を緩やかにする値オブジェクト

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
IDDD本から理解するドメイン駆動設計連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 青木 淳夫(アオキ アツオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/10184 2017/06/02 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング