22.값을 참조로 전환 Change Value to Reference

동일한 인스턴스를 여러개 갖고 있는 클래스가 있고 여러개의 동일한 인스턴스를 하나의 객체로 바꾸고 싶다면
그 객체를 참조객체로 바꿔라.

많은 시스템에서 객체를 참조 객체와 값 객체로 분류할 수 있다. 참조 객체는 고객이나 계좌 같은 것이다. 각각의 객체는 실세계의 하나의 객체를 의미하고, 그들이 같은 지를 테스트 하기 위해서 동일한 객체인지(같은 인스턴스인지)를 확인한다. 값 객체는 날짜나 금액과 같다. 이것들은 순전히 가지고 잇는 값을 통해서 정의된다. 복사본이 있는지는 신경 쓰지 않는다. 시스템 내에서 ‘2000년1월1일’ 객체를 수백 개 가지고 있을 수도 있다. 두 객체가 같은 것인지를 판단하기 위해서는 equals 메소드(그리고 hashCode 메소드)를 오버라이드 해야 한다.

참조 객체를 쓸지 값 객체를 쓸지 결정하는 것이 항상 명확한 것은 아니다. 때로는 약간의 불변성(immutable) 데이터를 가지는 간단한 값으로 시작한다. 그리고 나중에는 변경 가능한 데이터를 두고, 변경이 그 객체를 참조하고 있는 모든 곳으로 전파되기를 바란다. 이 시점이 객체를 참조 객체로 바꾸어야 할 때이다.

※값객체(복사), 참조객체(원본)

Before
Class Order
{
    private Customer _customer;

    public string CustomerName {
        get { return _customer.Name; }
        set { _customer = new Customer(value); }
    }
    public Order(string customerName)
    {
        _customer = new Customer(customerName);
    }

    private static int NumberOfOrdersFor(IEnumerable<Order> orders, string customer)
    {
        return orders.Count(o => o.CutomerName.Equals(customer, stringComparison.InvariantCultureignoreCase));
    }
}

Class Customer
{
    public string Name { get; private set; }

    public Customer(string name)
    {
        Name = name;
    }

    public override bool Equals(object obj)
    {
        return Name.Equals(obj);
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

Customer 객체에서 고객을 미리 정의 해놓고
Order 객체에서 Cutomer객체의 존재하는 하나의 고객을 가져온다.

After
  public class Order
    {
        private Customer _customer;

        public string CustomerName
        {
            get { return _customer.Name; }
            set { _customer = Customer.GetExistingCustomer(value); }
        }

        public Order(string customerName)
        {
            _customer = Customer.GetExistingCustomer(customerName);
        }

        private static int NumberOfOrdersFor(IEnumerable<Order> orders, string customer)
        {
            return orders.Count(o => o.CustomerName.Equals(customer, StringComparison.InvariantCultureIgnoreCase));
        }
    }


    public class Customer
    {
        private static HashSet<Customer> ExistingCustomers = new HashSet<Customer>();

        static Customer()
        {
            ExistingCustomers.Add(new Customer("Hey, Inc"));
            ExistingCustomers.Add(new Customer("Goods Job, LLC"));
            // etc.
        }

        public string Name { get; private set; }

        private Customer(string name)
        {
            Name = name;
        }

        public static Customer GetExistingCustomer(string name)
        {
            return ExistingCustomers.Single(c => c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
        }

        public override bool Equals(object obj)
        {
            return Name.Equals(obj);
        }

        public override int GetHashCode()
        {
            return Name.GetHashCode();
        }
    }