객체지향 패러다임 3 (학점계산기)
객체지향 이해 세번째 학점 계산기 만들기입니다.
java/com/example/gradecalculator/GradeCalculatorTest.java
package com.example;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
* 요구사항
* • 평균학점 계산 방법 = (학점수×교과목 평점)의 합계/수강신청 총학점 수
* • MVC패턴(Model-View-Controller) 기반으로 구현한다.
* • 일급 컬렉션 사용
*/
public class GradeCalculatorTest {
// 학점 계산기 도메인: 이수한 과목(객체지향프로그래밍, 자료구조, 일본어회화), 학점 계산기 (객체 먼저 생각)
// 객체지향프로그래밍, 자료구조, 일본어회화 --> 과목(코스) 클래스 (정적인 타입으로 추상화)
// 이수한 과목을 전달하여 평균학점 계산 요청 ----> To 학점계산기 ----> (학점수×교과목 평점)의 합계 ----> To 과목(코스)
// ----> 수강신청 총학점 수 ----> To 과목(코스)
@DisplayName("평균 학점을 계산한다.")
@Test
void calculateGradeTest() {
List<Course> courses = List.of(new Course("OOP", 3, "A+"),
new Course("자료구조", 3, "A+"));
GradeCalculator gradeCalculator = new GradeCalculator(courses);
double gradeResult = gradeCalculator.calculateGrade();
assertThat(gradeResult).isEqualTo(4.5);
}
}
- 요구사항은 3가지입니다.
- 학점계산기의 객체는 '이수한 과목', '학점 계산기' 로 나뉠 수 있습니다. (객체)
- 과목에는 객체지향프로그래밍,자료구조,일본어회화가 있다고 가정합니다. (정적타입으로 추상화)
- 학점계산기(GradeCalculator)로 이수한 과목을 전달하여 평균학점 계산을 요청합니다.
- 요청받은 학점계산기는 과목클래스(Course)로 계산을 위임합니다.
- 테스트 메서드 calculateGradeTest() 는 학점계산기 객체에 이수한 과목,점수,학점이 들어있는 과목객체를 주입하고, 학점계산을 요청 후 결과를 확인합니다. 예) 자료구조 과목, "A+" --> 4.5
java/com/example/gradecalculator/Course.java
package com.example;
public class Course {
private final String subject; // 과목명
private final int credit; // 학점
private final String grade; // 성적 (A+, A, B+ ...)
public Course(String subject, int credit, String grade) {
this.subject = subject;
this.credit = credit;
this.grade = grade;
}
public double multiplyCreditAndCourseGrade() {
return credit * getGradeToNumber();
}
public int getCredit() {
return credit;
}
public double getGradeToNumber() {
double grade = 0;
switch (this.grade) {
case "A+":
grade = 4.5;
break;
case "A":
grade = 4.0;
case "B+":
grade = 3.5;
break;
case "B":
grade = 3.0;
break;
case "C+":
grade = 2.5;
break;
case "C":
grade = 2.0;
break;
}
return grade;
}
}
- 과목(Course) 객체입니다.
- 과목명, 학점, 성적을 필드변수로 가지고, 계산,변환 메서드가 있습니다.
java/com/example/gradecalculator/GradeCalculator.java
package com.example;
import java.util.List;
public class GradeCalculator {
private final List<Course> courses;
public GradeCalculator(List<Course> courses) {
this.courses = courses;
}
/**
* 요구사항
* • 평균학점 계산 방법 = (학점수×교과목 평점)의 합계/수강신청 총학점 수
* • MVC패턴(Model-View-Controller) 기반으로 구현한다.
* • 일급 컬렉션 사용
*/
public double calculateGrade() {
// (학점수×교과목 평점)의 합계
double multipliedCreditAndCourseGrade = 0;
for (Course course : courses) {
multipliedCreditAndCourseGrade += course.multiplyCreditAndCourseGrade();
// course.multiplyCreditAndCourseGrade();
// 응집도가 높다 --> 변화가 생길때 한군데만 수정하면 된다.
// getter로 정보를 가져와서 처리하는 것이 아닌 해당 데이터를 가진 객체에게 메세지를 줘서 작업을 처리하게 하면 변화에 유연한 코드를 짤 수 있다.
}
// 이수한 과목들의(courses) 수강신청 총 학점 수
int totalCompletedCredit = courses.stream()
.mapToInt(Course::getCredit)
.sum();
return multipliedCreditAndCourseGrade / totalCompletedCredit;
}
}
- 학점계산기 객체입니다.
- 주입받은 과목 List 의 계산을 위임하고 (학점x교과목평점) 값을 multipliedCreditAndCourseGrade 에 저장합니다.
- 이수한 과목들의 수강신청 총 학점수를 totalCompletedCredit 에 저장합니다.
- 평균학점 계산은 multipliedCreditAndCourseGrade / totalCompletedCredit 입니다.
이번에는 객체들끼리 협력하는 방식으로 리팩토링입니다.
일급 컬렉션을 사용합니다.
일급 컬렉션(First-Class Collection)이란?
Java에서 일급 컬렉션(First-Class Collection)은 다른 객체와 동등한 지위를 갖는 컬렉션 객체를 말합니다.
일급 컬렉션은 다음과 같은 특징을 가집니다.
- 컬렉션 객체는 변수나 매개변수에 할당할 수 있다.
- 컬렉션 객체는 다른 객체와 동등한 지위를 가진다.
- 컬렉션 객체는 반환값으로 사용할 수 있다.
- 컬렉션 객체는 필요한 경우 메서드에서 생성할 수 있다.
- 그냥 간단하게 한 문장으로 말하면 Collection을 Wrapping 하면서, 그 외 다른 멤버 변수가 없는 상태를 일급 컬렉션이라 합니다.
(출처: https://dkswnkk.tistory.com/696)
java/com/example/gradecalculator/Courses.java (일급 컬렉션)
package com.example.gradecalculator;
import java.util.List;
// 일급 컬렉션 -> 여러개의 Course 정보를 가진 클래스(List, set 형태 등)
// Course 의 정보로 처리할 수 있는 책임들이 해당 일급 컬렉션 클래스 밑으로 모두 이동
// 수정사항이 생겼을 때 이 클래스 안에서 메서드만 수정하면 된다.
public class Courses {
private final List<Course> courses;
public Courses(List<Course> courses) {
this.courses = courses;
}
public double multiplyCreditAndCourseGrade() {
return courses.stream() // 이수한 과목들을 전체 돌면서 과목들의 학점수*성적정보를 모두 sum()
.mapToDouble(Course::multiplyCreditAndCourseGrade)
.sum();
}
public int calculateTotalCompletedCredit() {
return courses.stream() // 이수한 과목들을 전체 돌면서 해당하는 학점들을 모두 sum()
.mapToInt(Course::getCredit)
.sum();
}
}
java/com/example/gradecalculator/GradeCalculator.java
package com.example;
import java.util.List;
public class GradeCalculator {
private final Courses courses;
public GradeCalculator(List<Course> courses) {
this.courses = new Courses(courses);
}
/**
* 핵심 포인트
*/
// 이수한 과목을 전달하여 평균학점 계산 요청 ----> To 학점계산기 ----> (학점수×교과목 평점)의 합계 ----> To 과목(코스) 일급 컬렉션
// ----> 수강신청 총학점 수 ----> To 과목(코스) 일급 컬렉션
public double calculateGrade() {
// (학점수×교과목 평점)의 합계
double totalMultiplyCreditAndCourseGrade = courses.multiplyCreditAndCourseGrade();
// 이수한 과목들의(courses) 수강신청 총 학점 수
int totalCompletedCredit = courses.calculateTotalCompletedCredit();
return totalMultiplyCreditAndCourseGrade / totalCompletedCredit;
}
}
- 일급컬렉션을 사용하여 계산을 위임합니다.