26.컬렉션 캡슐화 Encapsulate Collection

Before
 class Person
 {
   public List<Course> Course { get; set; }
 }

class Course
{
   public string Name { get; set; }
   public bool IsAdvanced { get; set; }
}

class Simple_Example
{
  public void ManipulatingCourses()
  {
      var kent = new Person() { Course = new List<Course>() };
      kent.Course.Add(new Course { Name = "Smalltalk Programming", IsAdvanced = false });
      kent.Course.Add(new Course { Name = "Appreciating Single Malts", IsAdvanced = true });
      var refactoringCourse = new Course { Name = "Refactioring", IsAdvanced = false };
      kent.Course.Add(refactoringCourse);
      kent.Course.Add(new Course { Name = "Brutal Sarcasm", IsAdvanced = true });
      kent.Course.Remove(refactoringCourse);
  }

  public void Getting()
  {
      var kent = new Person();
      // more code 
      var advencedCourses = kent.Course.Count(c => c.IsAdvanced);
  }
}

컬렉션을 리턴하는 메소드가 있으면 그 메소드가 읽기전용 뷰를 리턴하도록 만들고, add/remove 메소드를 제공하라.
get 메소드가 컬렉션 자체를 리턴하면 안된다. 이유는 클라이언트 코드가 컬렉션을 가지고 있는 클래스가 알지 못하는 사이에 컬렉션의 내용을 조작할 수 있기 때문이다. get 메소드는 컬렉션을 조작하지 못하도록 하여 리턴 해야 한다.
또한 set 메소드도 있으면 안 된다. 대신 컬렉션의 요소를 추가, 삭제하는 작업을 제어할 수 있게 된다.

After
  class Person
    {
        private List<Course> _courses;
        public IReadOnlyList<Course> Courses   //  읽기 전용 collection
        {
            get { return _courses.AsReadOnly();  } // 현재 collection에 대한 읽기 전용 list 반환
        }

        public Person()
        {
            _courses = new List<Course>();
        }

        //public Person(IEnumerable<Course> courses)  기본 타입 생성자 동시에 실행
        //    :this()
        //{
        //    _courses.AddRange(courses);
        //}

        public void AddCourse(Course course)    //  add 메소드 제공
        {
            _courses.Add(course);
        }

        public void RemoveCourse(Course course) //  remove 메소드 제공
        {
            _courses.Remove(course);
        }
    }

    class Course
    {
        public string Name { get; set; }
        public bool IsAdvanced { get; set; }
    }

    class Simple_Example
    {
        public void ManipulatingCourses()
        {
            var kent = new Person();
            kent.AddCourse(new Course { Name = "Smalltalk Programming", IsAdvanced = false });
            kent.AddCourse(new Course { Name = "Appreciating Single Malts", IsAdvanced = true });

            var refactoringCourse = new Course { Name = "Refactioring", IsAdvanced = false };
            kent.AddCourse(refactoringCourse);

            kent.AddCourse(new Course { Name = "Brutal Sarcasm", IsAdvanced = true });
            kent.RemoveCourse(refactoringCourse);
        }

        public void Getting()
        {
            var kent = new Person();
            // more code 
            var advencedCourses = kent.Courses.Count(c => c.IsAdvanced);
        }
    }