본문 바로가기

디자인패턴/내 코드가 그렇게 이상한가요?

List 등 컬렉션 처리를 캡슐화하기 - 내 코드가 그렇게 이상한가요? 7장 요약 (2)

컬렉션 처리를 캡슐화하기란?

클래스가 리스트를 멤버 변수로 가지는 경우, 이 리스트를 조작하는 로직은 모두 해당 클래스 내부에만 구현하고 외부에서는 조작할 수 없게 닫는 것을 말한다.

 

Party와 member관련 코드 예시

예를 들면 Party라는 클래스가 다음과 같이 List<Member> mebers를 가지는 경우이다.

class Party {
    List<Member> members;
    
    Party() {
        members = new ArrayList<>();
    } 
}

 

 

 

나쁜 코드 예시

1) 파티에 멤버 추가, 2) 파티의 생존 여부 판별과 같은 로직이 Party 클래스가 아닌 다른 클래스들에서 마구잡이로 등장한다.

class FieldManager {
    void addMember(List<Member> members, Member newMember) {
        if (members.stream().anyMatch()(member -> member.id == newMember.id)) {
            throw new RuntimeException("이미 존재하는 멤버");
        }
        
        if (member.size() == 30) {
            throw new RuntimeException("정원 초과");
        }
    }
}

 

 

좋은 코드 예시1 - 멤버 변수는 private으로 선언한다.

class Party {
    private final List<Member> members;
    
    Party() {
        members = new ArrayList<>();
    } 
}

 

 

좋은 코드 예시2 - 반환할 때는 new 키워드로 새로운 인스턴스를 반환한다.

사이드이펙트가 발생하는 것을 방지하기 위해서 객체를 반환할 때는 new 키워드를 활용하여 항상 새로운 인스턴스를 반환하도록 한다.

class Party {
     Party addMember(final Member newMember) {
         List<Member> newList = new ArrayList<>();
         newList.add(newMember);
         return new Party(newList);
     }
}

 

 

좋은 코드 예시3 - 외부로 전달할 때는 불변으로 만들어 전달한다.

컬렉션을 그대로 반환하면 외부에서 리스트를 마음대로 조작할 수 있다. 이때 `unmodifiableList` 메서드를 사용한다.

class Party {
    List<Member> getMembers() {
        return members.unmodifiableList();
    }
}