<자바와 JUnit을 활용한 실용주의 단위 테스트> 책과 Junit 5, AssertJ 공식문서를 참고하였습니다.
💡 세부 로직을 추출하여 메서드의 복잡성을 줄여라
public boolean matches(Criteria criteria) {
score = 0;
boolean kill = false;
boolean anyMatches = false;
for (Criterion criterion: criteria) {
Answer answer = answers.get(criterion.getAnswer().getQuestionText());
boolean match = criterion.getWeight() == Weight.DontCare ||
answer.match(criterion.getAnswer());
if (!match && criterion.getWeight() == Weight.MustMatch) {
kill = true;
}
if (match) {
score += criterion.getWeight().getValue();
}
anyMatches |= match;
}
if (kill) return false;
return anyMatches;
}
public boolean matches(Criteria criteria) {
score = 0;
boolean kill = false;
boolean anyMatches = false;
for (Criterion criterion: criteria) {
Answer answer = answers.get(criterion.getAnswer().getQuestionText());
boolean match = matches(criterion, answer);
if (!match && criterion.getWeight() == Weight.MustMatch) {
kill = true;
}
if (match) {
score += criterion.getWeight().getValue();
}
anyMatches |= match;
}
if (kill) return false;
return anyMatches;
}
private boolean matches(Criterion criterion, Answer answer) {
return criterion.getWeight() == Weight.DontCare ||
answer.match(criterion.getAnswer());
}
고수준의 matches(Criteria criteria)
저수준의 matches(Criterion criterion, Answer answer)
Profile 이 Criteria 객체를 어떻게 매칭하는지에만 관심이 있다면?
→ 저수준의 matches 가 어떻게 매치되는지 신경 쓰지 않아도 된다 !
→ 복잡도가 줄었다 ! ദ്ദി˘•ω•˘ )
위에서 메서드로 추출한 matches(Criterion criterion, Answer answer) 는 Profile 객체와 관련이 없다. 그럼 파라미터인 Criterion 과 Answer 를 보자.
public class Answer {
private int i;
private Question question;
// ...
public class Criterion implements Scoreable {
private Weight weight;
private Answer answer;
private int score;
// ...
Criterion 이 멤버 변수로 Answer 를 가지고(알고) 있다. 즉, Criterion 객체는 Answer 객체를 의존한다. 이제 matches() 를 이동할 건데 Answer 에 이동하면 Criterion 과 Answer 객체는 양방향 의존관계가 되어 좋지 않다. 그러니 Criterion 객체로 이동시키자.
public class Criterion implements Scoreable {
private Weight weight;
private Answer answer;
private int score;
// ...
public boolean matches(Answer answer) {
return getWeight() == Weight.DontCare || answer.match(getAnswer());
}
}
이제 Profile 클래스도 수정하자.
public boolean matches(Criteria criteria) {
score = 0;
boolean kill = false;
boolean anyMatches = false;
for (Criterion criterion: criteria) {
Answer answer = answers.get(criterion.getAnswer().getQuestionText());
boolean match = criterion.matches(answer);
if (!match && criterion.getWeight() == Weight.MustMatch) {
kill = true;
}
if (match) {
score += criterion.getWeight().getValue();
}
anyMatches |= match;
}
if (kill) return false;
return anyMatches;
}
리팩토링 후 복잡성도 줄었고 객체의 책임도 분명해졌다