システムに最適な値が必ずしもプリミティブな値とは限らない。システム固有の値を「値オブジェクト」と呼ぶ

class FullName
{
  public FullName(string firstName, string lastName)
  {
    FirstName = firstName;
    LastName = lastName;
  }
 
  public string FirstName{get;}
  public string LastName{get;}
}

値の性質

不変である

"こんにちわ".ChangeTo("Hello"); //本来存在しないメソッド
Console.WriteLine("こんにちわ"); // Helloが表示される

交換が可能である

「変更」ではなく「交換」する

// NG
var fullName = new FullName("masanobu", "naruse")
fullName.changeName("masanobu", "sato")
 
// OK
var fullName = new FullName("masanobu", "naruse")
fullName = new FullName("masanobu", "sato")

等価性によって比較される

等価性は値オブジェクトの属性で比較するのではなく、値オブジェクト自身で比較する

var nameA = new FullName("masanobu", "naruse");
var nameB = new FullName("masanobu", "sato");
 
// NG
var compareResult = nameA.FirstName == nameB.FirstName
  && nameA.LastName == nameB.LastName;
 
// OK
compareResult = nameA.Equals(nameB);

ふるまい

値オブジェクトには振る舞いをもたせられる。

ふるまいをもたせると、そのオブジェクトができることがわかる = 仕様がわかる

class Money
{
  private readonly decimal amount;
  private readonly string currency;
 

 
  public Money Add(Money arg) {
    if (arg == null) throw new ArgumentNullException(nameof (arg));
    if (currency != arg.currency) throw new ArgumentException("通貨単位が異なります")
 
    return new Money(amount + arg.amount, currency)
  }
}