배열과 List와 같은 컬렉션에 관련된 테크닉을 알아보자
컬렉션 요소들 가운데 조건을 만족하는지 확인하는 방법
anyMatch
활용하기 (가독성 good)바퀴의 재발명
을 방지하기 위해 미리 프레임워크의 기능과 라이브러리를 잘 확인하자.
컬렉션 요소 중 특정 조건을 만족하는 요소에 대해서만 작업을 수행하고자 할 경우.
for loop + if 조건문 + if 조건문 중첩
: 가독성 똥망for loop + if 조건문 + continue
: continue로 중첩 조건문을 제거할 수 있음// for loop + if 조건문 + if 조건문 중첩
for (Member member : members) {
if (0 < member.hitPoint) {
if (member.containsState(StateType.poison) {
member.hitPoint -= 10;
if (member.hitPoint <= 0) {
member.hitPoint = 0;
member.addState(StateType.dead);
member.removeState(StateType.poison);
}
}
}
}
// for loop + if 조건문 + continue
for (Member member : members) {
if (member.hitPoint == 0) {
continue;
}
if (member.containsState(StateType.poison) {
continue;
}
member.hitPoint -= 10;
if (member.hitPoint <= 0) {
continue;
}
member.hitPoint = 0;
member.addState(StateType.dead);
member.removeState(StateType.poison);
}
for loop + if 조건문 + else break
: 가독성 똥망for loop + if 반전 조건문 + break
: early-return 처럼 for loop에서 조건을 반전하고 break.// for loop + if 조건문 + else break
int totalDamage = 0;
for (Member member : members) {
if (member.hasTeamAttackSucceeded()) {
int damage = (int) (member.attack * 1.1);
if (30 <= damage) {
totalDamage += damage;
} else {
break;
}
} else {
break;
}
}
// for loop + if 반전 조건문 + break
int totalDamage = 0;
for (Member member : members) {
if (!member.hasTeamAttackSucceeded()) {
break;
}
int damage = (int) (member.attack * 1.1);
if (30 > damage) {
break;
}
totalDamage += damage;
}
컬렉션에 요소를 추가할 경우, 데이터(컬렉션)와 기능(추가)이 분리되면 응집도가 낮아진다.
class FieldManager {
void addMember(List<Member> members, Member newMember) {
if (유효성_검사_1) {
throw new Exception("error1");
}
if (유효성_검사_2) {
throw new Exception("error2");
}
members.add(newMember);
}
boolean partyIsAlive(List<Member> members) {
return members.stream().anyMatch(Member::isAlive);
}
}
class SpecialEventManager {
// FieldManager#addMember 에서 유효성 검사 로직 누락
void addMember(List<Member> members, Member newMember) {
members.add(newMember);
}
}
class BattleManager {
// FieldManager#partyIsAlive 와 동일한 기능
boolean membersAreAlive(List<Member> members) {
for (Member member : members) {
if (member.isAlive()) return true;
}
return false;
}
}
List 라는 데이터에 대해 요소 추가
, 요소 중 조건 체크
와 관련된 기능이 분리되어 있기 때문에 응집도가 매우 낮아지게 된다
일급 컬렉션
: 컬렉션과 관련된 로직을 캡슐화하는 디자인 패턴
class Party {
private final List<Member> members;
Party() {
members = new ArrayList<>();
}
// members의 요소가 변경되는 부수효과를 방지한 add 메소드
Party add(final Member member) {
if (유효성_검사_1) {
throw new Exception("error1");
}
if (유효성_검사_2) {
throw new Exception("error2");
}
List<Member> adding = new ArrayList<>(members);
adding.add(member);
return new Party(adding);
}
boolean isAlive() {
return members.stream().anyMatch(Member::isAlive);
}
}
일급 컬렉션의 인스턴스 변수를 외부로 그대로 노출하면, 인스턴스 변수에 요소를 추가하고 제거하여 부수효과가 발생한다.
class Party {
private final List<Member> members;
List<Member> members() {
return members.unmodifiableList();
}
}