객체지향 생활체조 원칙은 소트웍스 앤솔러지(ThoughtWorks Anthology) 라는 책에 나오는 원칙이다.

목차

  1. 한 메서드에 오직 한 단계의 들여쓰기(indent)만 한다.
  2. else 예약어를 사용하지 않는다.
  3. 모든 원시 값과 문자열을 포장한다.
  4. 일급 컬렉션을 쓴다.
  5. 한 줄에 점을 하나만 찍는다.
  6. 줄여 쓰지 않는다 ( 축약 금지 )
  7. 모든 엔티티를 작게 유지한다.
  8. 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
  9. Getter / Setter / Property를 쓰지 않는다.
축약 금지

 

클래스, 메서드, 변수명의 이름을 줄여쓰지 말자는 규칙입니다.

 

이전시간에 예제로 사용되었던 StudentList 객체를 가져오겠습니다.

 

public class StudentList {

    private final List<Student> students;

    public StudentList() {
        this.students = new ArrayList<>();
    }

    public void add(Student student) {
        validateStudentsSize();
        validateStudentName(student);

        students.add(student);
    }
    
    // 이하 생략 ...
}

 

객체지향 생활체조 원칙 3. 모든 원시값과 문자열을 포장한다. 편 부터 읽으신분들은 이 코드를 보자마자 add 메서드는 Student 객체를 검증하고 List에 넣는 메서드라는것을 아실겁니다. 하지만 처음보는사람이 이 코드를 본다면 어떤 역할을 하는지 유추하기에는 어려움이 있죠. 물론 예제코드가 어렵지 않아 예상이 가겠지만 코드가 더 복잡해지고 일이 많아진다면 더욱 어려워질 것입니다.

 

따라서 이름을 바꿔보겠습니다.

 

public class StudentList {

    private final List<Student> students;

    public void addStudent(Student student) {
        validateStudentsSize();
        validateStudentName(student);

        students.add(student);
    }
    
    // 이하 생략 ...
}

 

이렇게만 바꿔주어도 의미가 명확해집니다.

 

 

축약금지의 의미는 정말 간단합니다. 일에 대한 명확한 이름을 지정해주어 혼동을 주지 말라는 의미입니다.

객체지향 생활체조 원칙은 소트웍스 앤솔러지(ThoughtWorks Anthology) 라는 책에 나오는 원칙이다.

목차

  1. 한 메서드에 오직 한 단계의 들여쓰기(indent)만 한다.
  2. else 예약어를 사용하지 않는다.
  3. 모든 원시 값과 문자열을 포장한다.
  4. 일급 컬렉션을 쓴다.
  5. 한 줄에 점을 하나만 찍는다.
  6. 줄여 쓰지 않는다 ( 축약 금지 )
  7. 모든 엔티티를 작게 유지한다.
  8. 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
  9. Getter / Setter / Property를 쓰지 않는다.

 

한 줄에 점을 하나만 찍는다.

 

 

단순히 한 줄에 점의 개수를 헤아려 줄이라는것이 아닙니다. 점을 찍는 행위는 인스턴스의 접근을 하는 행위로 이는 호출자와 피호출자와의 결합도가 강하게 형성된다는 의미입니다.

 

이전시간인 일급 컬렉션에서 사용되었던 List<Student> students를 예시로 사용해보겠습니다.

 

public class Student {

    private Name name;
    private Age age;
    private Score score;
    
    .. Getter
}

Score 객체를 추가로 넣었습니다. 내부에는 int score가 존재합니다.

 

List<Student> 내에서 가장 점수가 높은 학생을 선발한다고 가정한다면

public static void main(String[] args) {
    List<Student> students = new ArrayList<>();
    
    Student student = getTopScoreStudent(students);

}

private Student getTopScoreStudent(List<Student> students) {
    Student topStudent = null;
    for (Student student : students) {
        if (topStudent == null) {
            topStudent = student;
            continue;
        }
        if (topStudent.getScore().getScore() < student.getScore().getScore()) {
            topStudent = student;
        }
    }
    return topStudent;
}

이렇게 작성될것입니다. 하지만 처음에 언급했듯이 이 클래스와 Score와는 아무런 관계가 없습니다 즉, 불필요한 결합도가 높아졌다는 것을 의미합니다. 만약 Student 객체에 대한 변경이 생긴다면? Score 객체에 대한 변경이 생긴다면? Score 의 멤버변수 타입이 변경된다면? 당연하게도 위에 메서드를 사용하고있는 객체에 변경이 불가피합니다. 그리고 변경과정에서 오류의 가능성도 증가하겠죠.

 

그럼 어떻게 해야하는지 차근차근 알아봅시다.

 

 

먼저 저번시간에 만들었던 것처럼 일급클래스를 적용시켜줍니다.

public class StudentList {

    private final List<Student> students;

    public Student getTopScoreStudent() {
        Student topStudent = null;
        for (Student student : students) {
            if (topStudent == null) {
                topStudent = student;
                continue;
            }

            if (topStudent.getScore().getScore() < student.getScore().getScore()) {
                topStudent = student;
            }
        }
        return topStudent;
    }
    
    // 나머지 메서드 ...
}

 

일급 클래스만 적용시켜도 Main 클래스와의 결합도가 낮아졌습니다.

 

 

이제 Student 객체로 일을 넘겨보겠습니다.

public class StudentList {

    private final List<Student> students;

    public Student getTopScoreStudent() {
        Student topStudent = null;
        for (Student student : students) {
            // 생략 ...

            topStudent = topStudent.compareScore(student);
        }
        return topStudent;
    }
    
    // 나머지 메서드 ...
}

public class Student {

    private Name name;
    private Age age;
    private Score score;

    public Student compareScore(Student student) {
        if (score.getScore() < student.getScore().getScore()) {
            return student;
        }
        return this;
    }
}

 

이제 마지막으로 Score 객체에 일을 넘겨보겠습니다.

 

public class Student {

    private Name name;
    private Age age;
    private Score score;

    public Student compareScore(Student student) {
        Score compareScore = score.compareScore(student.getScore());
        if (this.score == compareScore) { // 같은 주소값을 반환하기 때문에 == 를 사용했습니다.
            return this;
        }
        return student;
    }
    
    // 이하 생략 ...
}

public class Score {

    private int score;

    public Score(int score) {
        this.score = score;
    }
    public Score compareScore(Score arguScore) {
        if (score < arguScore.getScore()) {
            return arguScore;
        }
        return this;
    }
    
    // 이하 생략 ...
}

 

기존 코드와 달리 하위 객체의 일을 알 필요가 없어졌고 그저 자신의 일만 하게 되었습니다.

이로써 Main - StudentList - Student - Score 간에 결합도를 완전히 낮췄습니다.

 

결국 이 한 줄에 한 점을 찍는다는 의미는 자신이 알고있는 객체하고만 상호작용하면 되고 제 3자인 객체하고는 상호작용하지 않음으로써 결합도를 약하게 만들어 종속성을 최소화 시키는것입니다.

 

+ Recent posts