79


WHAT

  • Collection을 Wrapping 한다.
  • 그 외 다른 변수가 없는 클래스.

WHY

HOW


무슨차이?

1. 비지니스에 종속적인 자료구조

  • 클래스 내부적으로 비즈니스 검증 로직을 관리 할 수 있다
  • 아니라면 선언한 모든 곳에서 검증로직이 각각 들어가야해
  • Email 관련된 요구사항은 Email에서만 관리하게 됨
  • 응집도가 높아지고 User와 Email의 결합도는 낮출 수 있다.
#### As-Is
 
public class User
{
    private List<Email> _emails = new List<Email>();
 
    public bool AddEmail(Email email)
    {
        if (_emails.Count >= 10)
            return false;
 
        if (_emails.Any(x => x.Equals(email)))
            return false;
 
        _emails.Add(email);
        return true;
    }
}
#### To-Be
 
public class User
{
    private Emails _emails { get; set; }
 
    public bool AddEmail(Email email)
    {
        return _emails.AddEmail(email);
    }
}
 
public class Emails
{
    private List<Email> _emails = new List<Email>();
 
    public bool AddEmail(Email email)
    {
        if (_emails.Count >= 10)
            return false;
 
        if (_emails.Any(x => x.Equals(email)))
            return false;
 
        _emails.Add(email);
        return true;
    }
}

2. 불변성 보장

  • 캡슐화를 통해 보장
  • readonly는 재할당만 금지할 뿐이니까, Add, Remove 등이 가능하거든
  • 하지만 일급컬렉션은 Setter만 안만들면 해결됨
public class Emails
{
    private readonly List<Email> _emails;
 
    public Emails(List<Email> emails)
    {
        _emails = emails;
    }
 
    public Email this[int index] 
    { 
	    get => new Email(_emails[index].Local, _emails[index].Domain); 
	}
}

3. 상태와 행위를 한 곳에서 관리

  • 값과 로직이 함께 존재하기 때문에 응집도가 높아짐
As-Is
  • 선언하는 곳이 많아지면 기능 중복이 일어난다.
public class User
{
    private List<Email> _emails { get; set; }
    public bool AddEmail(Email email)
    {
        if (_emails.Count >= 10)
            return false;
 
        if (_emails.Any(x => x.Equals(email)))
            return false;
 
        _emails.Add(email);
        return true;
    }
}
public class Manager
{
    private List<Email> _emails { get; set; }
    public bool AddEmail(Email email)
    {
        if (_emails.Count >= 10)
            return false;
 
        if (_emails.Any(x => x.Equals(email)))
            return false;
 
        _emails.Add(email);
        return true;
    }
}
To-Be
  • 일급 컬렉션을 사용하게 되면 응집도가 높아지기 때문에 비즈니스 로직이 변경 되어도 Emails Class만 수정하면 된다.
public class User
{
    private Emails _emails { get; set; }
 
    public bool AddEmail(Email email)
    {
        return _emails.AddEmail(email);
    }
}
public class Manager
{
    private Emails _emails { get; set; }
    public bool AddEmail(Email email)
    {
        return _emails.AddEmail(email);
    }
}
 
public class Emails
{
    private readonly List<Email> _emails;
 
    public Emails()
    {
        _emails = new List<Email>();
    }
 
    public bool AddEmail(Email email)
    {
        if (_emails.Count >= 10)
            return false;
 
        if (_emails.Any(x => x.Equals(email)))
            return false;
 
        _emails.Add(email);
        return true;
    }
}

4. 이름이 있는 컬렉션

  • 변수에서만 파악 가능하던 비즈니스가 컬렉션 자체에서 확인 가능하다.
  • 변수로만 관리된다면 각자 어떻게 선언했을지도 모르고, 획일화도 안되어 있을것.
  • 예를들어 NaverEmail에 대한 요구사항이 변경되었다면 쉽게 참조하는 코드를 모두 찾을 수 있을 것이다.
### As-Is
public class User
{
    private List<Email> _mireroEmails { get; set; }
    private List<Email> _naverEmails { get; set; }
}
 
### To-Be
public class User
{
    private MireroEmails _mireroEmails { get; set; }
    private NaverEmails _naverEmails { get; set; }
}