コンピュータサイエンスでは、値オブジェクトは、同一性に基づかない等価性を持つエンティティを表す小さなオブジェクトです。つまり、2 つの値オブジェクトは、同じオブジェクトである必要はなく、同じ値を持つ場合に等しいとみなされます。[ 1 ] [ 2 ]
値オブジェクトの例としては、金額や日付範囲を表すオブジェクトが挙げられます。
小さいため、同じエンティティを表す同じ値オブジェクトの複数のコピーを持つことができます。単一のインスタンスに依存してそれへの参照を使用するよりも、新しいオブジェクトを作成する方が簡単な場合が多いです。[ 2 ]
値オブジェクトは不変であるべきです。[ 3 ]これは、同じ値オブジェクトが作成された場合、同じ値のまま維持されるという暗黙の契約に必要です。また、クライアントコードがインスタンス化後に値オブジェクトを無効な状態にしたり、バグのある動作を導入したりできないため、値オブジェクトが不変であることは有用です。[ 4 ]
値オブジェクトは、DDDの構成要素の一つです。
オブジェクト指向プログラミング言語にはそれぞれ微妙な違いがあるため、値オブジェクトを実装および使用するための独自の方法とパターンが存在する。
C#では、クラスは参照型ですが、構造体 ( C 言語の構造体から派生した概念) は値型です。[ 5 ]したがって、クラス定義から派生したインスタンスはオブジェクトですが、構造体定義から派生したインスタンスは値オブジェクトであると言われます (正確には、構造体は属性をreadonly として宣言することで、値オブジェクトを表すために不変にすることができます[ 6 ] )。
C#クラスに値オブジェクトのプロパティを追加するには、以下の手順を実行します。
Object.Equalsオブジェクトがビジネスロジックを使用して比較されるように、メソッドをオーバーライドします。==、メソッド!=を使用するようにしますEquals。Object.GetHashCode、同じ等価性を持つオブジェクトについてはハッシュ値が同じになるようにします。例:
公開レコードStreetAddress (文字列Street 、文字列City );または、より冗長な構文で:
public class StreetAddress { public StreetAddress ( string street , string city ) { Street = street ; City = city ; }public string Street { get ; } public string City { get ; } }C++では、代入演算子をオーバーロードし、フィールド(コンストラクタの初期化リストによって一度評価される)とクラスのメソッドに適切な定数制約を使用することで、値オブジェクトを構築できます。
ただし、フィールド自体が const として宣言されている場合 (「getter」アクセサのみを公開しながら非 const フィールドを使用する場合ではなく)、そのような値オブジェクトを別の値オブジェクトで完全に上書きすることはできません ( object1 = object2)。
Pythonには等価性テストを提供するデータクラスがあり、パラメータを使用して不変にすることができますfrozen。[ 9 ]
from dataclasses import dataclass@dataclass ( frozen = True ) class StreetAddress : """番地を表します。"""通り:str都市:str値オブジェクトは、Java 14 以降、データレコードとして利用可能です[ 10 ]
C#やC++とは異なり、Javaは言語レベルでカスタム値型をサポートしていません。すべてのカスタム型は参照型であり、そのため同一性と参照のセマンティクスを持ちますが[ 11 ]、カスタム値型のサポートを拡張することが検討されています[ 12 ] 。
そのため、Javaプログラマーは不変オブジェクトを作成することで値オブジェクトをエミュレートします[ 13 ]。オブジェクトの状態が変わらない場合、参照を渡すことは意味的に値オブジェクトをコピーすることと同等だからです。
クラスを不変にするには、すべての属性をblank finalと宣言し、[ 14 ]すべての属性をArrayListやDateのような可変型ではなく、不変型 ( String、Integer、またはこれらのルールに従って宣言されたその他の型など) であると宣言します。また、参照ではなく値を比較するために equals と hashCode を定義する必要があります。
「VALJO」(VALue Java Object)という用語は、正しく定義された不変値オブジェクトに必要なより厳格なルールセットを指すために作られました。[ 15 ]
public class StreetAddress { public final String street ; public final String city ;public StreetAddress ( String street , String city ) { this.street = street ; this.city = city ; } public boolean equals ( StreetAddress that ) { return getClass ( ) == that.getClass ( ) && street == that.street && city == that.city ; } public int hashCode ( ) { return Objects.hash ( street , city ) ; } }Java 14 :
公開レコードStreetAddress ( String street , String city ) {}データクラスStreetAddress ( val street : String , val city : String )Kotlinでは、クラス本体の前にコンストラクタショートカット(本体が存在する場合)を持つことができ、これはフィールドの宣言とそれらのフィールドへの代入を兼ねます。`data`キーワードを追加すると、`equals`や`hashCode`などの実装が生成されます。
Ruby は、クラス (Ruby 3.2 で導入)を介して不変値オブジェクトData.defineをサポートしており、等価性、ハッシュ、および不変性を自動的に提供します。[ 16 ]
StreetAddress = Data.define ( : street , : city ){{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)