值物件

计算机科学裡的值物件（value object）是表示簡單實體的小型物件，這類實體的相等只根據其值，不依照其，只要兩個值物件的值相等，即視為相等，這兩個物件不需是同一個物件。

值物件的例子像是錢的總金額，以及日期範圍等。

值物件很小，因此可以將值物件複制數份，而這些值物件表示的是同一個實體，對於值物件，創建一個新物件會比只有一個實例，其他部份再參考此一實例要簡單。

值物件需是不可變物件：因為值物件的定義中隱含一件事，若兩個值物件相等，他們就需一直維持相等。讓值物件是不可變的也有其優點，因為客戶端的程式無法將值物件改為無效的狀態，或是在初始化後進行不正確的操作。

值物件常見於領域驅動設計（DDD）的建構模塊中。

實現
由於各種物件導向的程式语言之間有細微的差異，田此各語言在實現值物件和使用值物件上，都有自的方式以及设计模式。
 C# 
在C#裡，類別屬於引用類型，而結構體（概念源自C語言的结构体）是值類型。 
因此衍生自類別定義的實例是物件，而衍生自結構體定義的則是值物件（更準確的說法，結構體可以宣告屬性readonly，使結構體不可變，因而成為值物件
）。

以下的作法可以在C#類別中加入值物件的性質：
 重載方法，確保物件比較時是比較业务逻辑，不是其身份。
 运算符重载和的預設行為，使用方法。
 重載方法，確保兩個相等的物件有相同的hash。
 透過移除屬性setter，以及只從創建子傳遞成員的值的方式，讓類別不可變。

範例：public record StreetAddress(string Street, string City);

或是以下更多行的例子

public class StreetAddress
{
    public StreetAddress(string street, string city)
    {
        Street = street;
        City = city;
    }

    public string Street { get; }
    public string City { get; }
}
C++
C++裡的值物件可以用設定運算子的重載，再使用適當的常數限定符在欄位上（這樣就只會在創建時設定一次），以及類型的方法上。

不過，若欄位本身宣告為const，會有副作用，無法用另一個物件完全覆寫（）。若是用const以外的欄位，但是只開放getter存取函式，以此方式實現值物件，就可以做到用另一個物件完全覆寫的功能。

Python
Python有資料類別可以提供相關測試，並且可以用frozen參數設為不可變。

from dataclasses import dataclass

@dataclass(frozen=True)
class StreetAddress:
    """Represents a street address."""

    street: str
    city: str

Java
值物件在Java 14起開始支援，是data record。

Java和C#和C++不同，其沒有在語言層面支援自定義型態，每一個自定義型態都是參考性能，因此也會有身份和參考語意，不過仍有人在考慮如何支援自定義的值物件。

因此Java程式設計者會創建不可變的物件來模擬值物件，若物件的狀態不會變化，傳參考在語意上和複製值物件一樣。

可以將類別的所有屬性宣告為blank final,只有在构造器裡才能設定，宣告其中所有的屬性都是不可變的型態（例如、，或是依照其規則宣告的其他型態），不能使用像是甚至是的可變形態。也需要定義equals和hashCode，以其值進行比較，而不是使用參考。

已有人用VALJO（VALue Java Object）一詞來指正確定義地不可變值物件，需要符合的較嚴格規則。

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就變簡單了。

public record StreetAddress (String street, String city) {}

Kotlin
data class StreetAddress(val street: String, val city: String)

Kotlin裡，任何型態都可以有構造器shortcut在其型態本身之前（若該型態有本身的話），一方面是宣告欄位，也是設定這些欄位的值。若加上data關鍵字，就會用值物件的邏輯來實現equals和hashCode等。

Ruby
Ruby可以用Data.define類別來支援值物件（自Ruby 3.2導入），自動提供equality、hashing和 immutability.。

StreetAddress = Data.define(:street, :city)
相關條目
 数据传输对象
 領域驅動設計


參考資料

Category:物件 (電腦科學)