컴퓨터/이론 및 tools 사용

[리팩토링 refactoring ] Organizing Data 데이터 체계화 - Encapsulate Collection 컬렉션 캡슐화

review777777 2016. 11. 24. 03:08
반응형


Encapsulate Collection 컬렉션 캡슐화


Problem & Solution


클래스는 객체 컬렉션을 포함하는 필드를 포함
이 콜렉션은 배열,리스트, 세트 또는 벡터 일 수 있다.
컬렉션에 대한 작업을 위해 정상적인 getter 및 setter가 만들어짐.


그러나 컬렉션은 다른 데이터 유형에서 사용되는 프로토콜과 약간 다른 프로토콜에 의해 사용되야 한다.
 getter 메소드는 컬렉션 객체 자체를 반환하지 않아야한다.
 그러면 클라이언트가 소유자 클래스에 대한 지식없이 컬렉션 내용을 변경할 수 있기 때문
 클라이언트에 대한 오브젝트 데이터의 내부 구조가 너무 많이 보인다.
 콜렉션 요소를 가져 오는 메소드는 콜렉션을 변경할 수 없거나 구조에 대한 과도한 데이터를 공개 할 수없는 값을 리턴해야한다.

 컬렉션에 값을 할당하는 메서드가 있어서는 안된다
 대신 요소 추가 및 삭제 작업이 있어야한다. 
이로 인해 소유자 객체는 컬렉션 요소의 추가 및 삭제를 제어 할 수 있다.

이러한 프로토콜은 컬렉션을 적절하게 캡슐화하므로 궁극적으로 소유자 클래스와 클라이언트 코드 간의 연결 정도가 줄어 든다.

Problem



class Course {
  public Course(String name, boolean isAdvanced) {
    // ...
  }
  public boolean isAdvanced() {
    // ...
  }
}

class Person {
  private Set courses = new HashSet();

  public Set getCourses() {
    return Collections.unmodifiableSet(courses);
  }
  public void initializeCourses(Set arg) {
    Assert.isTrue(courses.isEmpty());
    courses.addAll(arg);
  }
  public void addCourse(Course arg) {
    courses.add(arg);
  }
  public void removeCourse(Course arg) {
    courses.remove(arg);
  }
  public int numberOfAdvancedCourses() {
    Iterator iter = getCourses().iterator();
    int count = 0;
    while (iter.hasNext()) {
      Course each = (Course) iter.next();
      if (each.isAdvanced()) {
        count++;
      }
    }
    return count;
  }
  public int numberOfCourses() {
    return courses.size();
  }
}

// Client code
Person kent = new Person();
kent.addCourse(new Course("Smalltalk Programming", false));
kent.addCourse(new Course("Appreciating Single Malts", true));
Assert.equals(2, kent.numberOfCourses());
Course refact = new Course("Refactoring", true);
kent.addCourse(refact);
kent.addCourse(new Course("Brutal Sarcasm", false));
Assert.equals(4, kent.numberOfCourses());
kent.removeCourse(refact);
Assert.equals(3, kent.numberOfCourses());

System.out.print("Advanced courses: " + kent.numberOfAdvancedCourses());




Solution




class Course {
  public Course(String name, boolean isAdvanced) {
    // ...
  }
  public boolean isAdvanced() {
    // ...
  }
}

class Person {
  private Set courses;

  public Set getCourses() {
    return courses;
  }
  public void setCourses(Set arg) {
    courses = arg;
  }
}

// Client code
Person kent = new Person();
Set s = new HashSet();
s.add(new Course("Smalltalk Programming", false));
s.add(new Course("Appreciating Single Malts", true));
kent.setCourses(s);
Assert.equals(2, kent.getCourses().size());
Course refact = new Course("Refactoring", true);
kent.getCourses().add(refact);
kent.getCourses().add(new Course("Brutal Sarcasm", false));
Assert.equals(4, kent.getCourses().size());
kent.getCourses().remove(refact);
Assert.equals(3, kent.getCourses().size());

Iterator iter = kent.getCourses().iterator();
int count = 0;
while (iter.hasNext()) {
  Course each = (Course) iter.next();
  if (each.isAdvanced()) {
    count++;
  }
}
System.out.print("Advanced courses: " + count);




컬렉션을 리턴하는 메소드가 있으면 그 메소드가 읽기전용 뷰를 리턴하도록 만들고, add/remove 메소드를 제공하라.

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



절차

1. 컬렉션 요소 추가 및 삭제 방법을 만든다. 매개 변수에 수집 요소를 받아 들여야한다.


2. 빈 생성자가 클래스 생성자에서 완료되지 않은 경우 필드에 초기 값으로 할당.


3. 수집 필드 설정 기의 호출을 찾는다. setter를 변경하여 요소 추가 및 삭제 작업을 사용하거나 이러한 작업이 클라이언트 코드를 호출하도록한다.


setter는 모든 콜렉션 요소를 다른 콜렉션 요소로 바꿀 때만 사용할 수 있다. 따라서 setter 이름 (Rename Method)을 바꿔서 바꾸는 것이 좋다.

4. 콜렉션이 변경된 콜렉션 게터의 모든 호출을찾는다. 

   컬렉션에서 요소를 추가 및 삭제하는 새 메서드를 사용하도록 코드를 변경


5. getter를 변경하여 컬렉션의 읽기 전용 표현을 반환


6. 콜렉션 클래스 자체의 내부에서 더 잘 보일 수있는 코드 용 콜렉션을 사용하는 클라이언트 코드를 조사



Benefits

• 컬렉션 필드는 클래스 내에 캡슐화된다. getter가 호출되면 컬렉션을 포함하는 클래스에 대한 지식없이 컬렉션 요소가 우연히 변경되거나 덮어 쓰지 않도록 컬렉션의 복사본을 반환한다.


• 컬렉션 요소가 배열과 같은 기본 유형 안에 포함되어 있으면 컬렉션 작업에보다 편리한 메서드를 만들 수 있다.


• 컬렉션 요소가 비 프리미티브 컨테이너 (표준 컬렉션 클래스)에 포함되어 있으면 컬렉션을 캡슐화하여 컬렉션의 원치 않는 표준 메소드에 대한 액세스를 제한 할 수 있다. (예 : 새 요소 추가 제한).

반응형