객체지향 설계 및 구현
- 도메인을 구성하는 객체에는 어떤 것들이 있는지 고민
- 객체들 간의 관계를 고민
- 동적인 객체를 정적인 타입으로 추상화해서 도메인 모델링 하기
- 협력을 설계
- 객체들을 포괄하는 타입에 적절한 책임을 할당
- 구현하기
(1) 학점계산기 도메인 : 이수한 과목, 학점 계산기 라는 객체들이 필요할 것 같다.
(2) 학점 계산기가 이수한 과목을 인스턴스 변수로 가지면서 평균학점을 계산할 수 있을 것 같다.
(3) 이수한 과목 : 객체지향프로그래밍, 자료구조, 중국어회화
객체지향프로그래밍, 자료구조, 중국어회화 --> 과목(코스) 클래스
객체는 3개지만 과목(코스)이라는 클래스로 표현할 수 있다는 것이
동적인 객체를 정적인 타입으로 추상화해서 도메인 모델링 하기 이다.
(4),(5) 과목(코스)에는 해당 자료구조가 3학점인지 2학점인지 정보를 가지고 있고 점수도 갖고 있다.
이수한 과목들을 전달 받은 학점 계산기는 학점수, 교과목 평점을 알고 있는 과목(코스)에게 이 합계에 대한 요청을 해서 이들에 대한 학점을 받고 또한 이수한 과목들의 총학점 수도 이수한 과목들을 통해서 구할 수 있기 때문에 각각의 합계와 총학점 수를 구해서 나눠서 전달해주면된다.
현재 아래 이미지의 코드에서의 개선해야할 부분은
Course가 과목에 대한 학점과 성적을 가지고 있는데
학점 x 성적 정보를 값을 가진 Course가 계산하지 않고 이들의 정보를 getter를 이용해서 가지고 와서 GradeCalculator라는 학점 계산기에서 수행하고 있다. 이것의 단점은 만약 (학점수×교과목 평점)의 합계 가 여러곳에서 사용이 된다면
즉 위의 이미지속 파란 부분이 여러 곳에서 사용된다고 가정했을 때
이 부분에 대한 로직이 바뀐다면 사용된 모든 곳을 수정해주어야한다.
즉 응집도가 약하다고 볼 수 있다.
그러나 이를 만약 Course에서 수행해준다면
기존의 getter를 이용하는 방식이 아니라 메시지를 이용해서 해당 객체에게 작업을 위임하는 형태로 변경했다.
이런 경우
return credit * getGradeToNumber() +1.0;
위의 한 줄 코드와 같이 1.0을 더해주는 변동사항이 생겨도 위 이미지의 파란 네모박스 친 부분만 바꾸어주면된다.
기존의 getter를 이용해서 가지고 오는 방식은 사용하는 곳 마다 찾아가서 1.0을 더해주어야 했다.
하지만 정보를 가진 객체에게 메시지(course.multiplyCreditAndCourseGrade())를 전달해서 해당 객체에서 작업을 수행 했더라면 해당 한 부분만 수정해 주면 된다.
즉, 응집도가 높기 때문에 변화가 발생했을 때 한 군데만 수정하면 되는 이점이 발생한다.
List<Course>
위 정보를 가지고 처리 할 수 있는 모든 책임들이 해당 일급 컬렉션 밑으로 모두 이동하게 된다.
예를 들어 해당 Course에 대한 총학점 수를 수정해달라고 하면
해당 메소드만 수정해주면 된다는 판단이 서게 된다.
또한
위와 같이 코드가 깔끔하게 리펙토링 된 모습을 볼 수 있다.
초반에 test 코드에 클래스들이 잘못 들어가 있었다.
위의 이미지가 맞는 경로이다.