학점계산기 구현에 앞서 필요한 과정들을 서술하면 다음과 같습니다:
구현 하기 전 생각하기
1. 요구사항 분석
- 평균 학점 계산 방식을 이해합니다. 평균학점 = [(학점 * 점수),..]의 합계 / [(학점),] 공식을 사용합니다.
- 학점 계산에 필요한 정보를 파악합니다. 예를 들어, 과목명, 학점, 점수 등이 필요합니다.
- 추가 요구사항을 확인합니다. 예를 들어, 과목이 전공인지 일반 과목인지 구분해야 할 수도 있습니다.
2. 도메인 모델 설계
Course클래스: 과목을 나타내며, 과목명, 학점(전공/일반 구분 포함), 점수(A+, A, B+ 등)를 속성으로 가집니다.Courses클래스(일급 컬렉션): 여러Course인스턴스를 하나의 컬렉션으로 관리하며, 전체 과목의 학점과 점수를 계산하는 메서드를 제공합니다.GradeCalculator클래스:Courses인스턴스를 받아 평균학점을 계산하는 기능을 수행합니다.GradeResult클래스: 계산된 평균학점과 총 이수학점을 저장합니다.
3. 핵심 로직 구현
- 과목 점수를 숫자로 변환하는 로직 구현:
Course클래스 내에서 점수(A+, A, B+ 등)를 숫자(4.5, 4.0, 3.5 등)로 변환하는 메서드를 구현합니다. - 학점과 점수의 곱을 계산하는 로직 구현:
Course클래스에서 학점과 점수의 곱을 계산합니다. - 전체 과목에 대한 학점과 점수의 곱의 합계 및 총 이수 학점을 계산하는 로직 구현:
Courses클래스에서 전체 과목의 학점과 점수의 곱의 합계와 총 이수 학점을 계산합니다. - 평균 학점을 계산하는 로직 구현:
GradeCalculator클래스에서 평균 학점을 계산합니다.
4. 테스트 코드 작성
- 각 클래스의 기능을 검증하는 단위 테스트를 작성합니다.
Course,Courses,GradeCalculator클래스의 메서드가 예상대로 작동하는지 확인합니다. - 평균 학점 계산 결과를 검증하는 통합 테스트를 작성합니다.
5. 리팩토링 및 최적화
- 코드의 가독성과 유지보수성을 개선합니다.
- 중복 코드를 제거하고, 필요하다면 설계를 개선합니다.
6. 문서화
- 주요 클래스와 메서드에 대한 설명을 주석으로 추가합니다.
- 사용 방법 및 예시를 문서화합니다.
코드 구현
package org.example.grade;
import org.example.grade.domain.Course;
import org.example.grade.domain.Courses;
import org.example.grade.domain.GradeCalculator;
import org.example.grade.domain.GradeResult;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.List;
import java.util.stream.Stream;
public class GradeCalculatorTest {
// 학점 계산기 도메인 : 이수한 과목(객체지향프로그래밍, 자료구조, 중국어회화), 학점 계산기
// 이수한 과목: 객체지향프로그래밍, 자료구조, 중국어회화 -> 과목(Course) 클래스
// 이수한 과목을 전달하여 평균학점 계산 요청 ---> 학점 계산기(학점수 + 교과목의 평점)의 합계 ----> 과목(코스)
// ----> 수창신청 총학점 수 ----> 과목(코스)
@DisplayName("사칙연산 테스트를 수행한다.")
@Test
void calculateGradeTest(){
// given
List<Course> courses = List.of(
new Course("OOP", Course.MAJOR_CREDIT, "A+"),
new Course("자료구조", Course.MAJOR_CREDIT, "A+"),
new Course("중국어회화", Course.GENERAL_CREDIT, "C")
);
// when
GradeCalculator gradeCalculator = new GradeCalculator(new Courses(courses));
GradeResult gradeResult = gradeCalculator.calculateGrade();
// then
System.out.println("이번 학기 학점: " + gradeResult.getAverageGrade() + " (총 " + gradeResult.getTotalCompletedCredit() + "학점)");
}
}
package org.example.grade.domain;
/**
* 과목을 나타내는 클래스입니다. 과목명, 학점, 그리고 점수를 관리합니다.
* 학점은 전공과 일반 과목으로 구분되며, 점수는 학점 계산에 사용됩니다.
*/
public class Course {
public static final int MAJOR_CREDIT = 3;
public static final int GENERAL_CREDIT = 2;
private final String subject;
private final int credit;
private final String grade;
/**
* Course 클래스 생성자.
*
* @param subject 과목명을 나타냅니다.
* @param credit 해당 과목의 학점입니다.
* @param grade 해당 과목의 점수입니다. (예: "A+", "B")
*/
public Course(String subject, int credit, String grade) {
this.subject = subject;
this.credit = credit;
this.grade = grade;
}
public int getCredit(){ return this.credit;}
/**
* 학점과 점수의 곱을 계산합니다.
*
* @return 과목의 학점과 점수의 곱입니다.
*/
public double multiplyCreditAndCourseGrade() { return credit * this.getGradeToNumber();}
/**
* 문자열로 된 점수를 숫자로 변환합니다.
*
* @return 변환된 숫자 점수입니다.
*/
private double getGradeToNumber() {
double gradeInt = 0;
switch (this.grade) {
case "A+":
gradeInt = 4.5;
break;
case "A":
gradeInt = 4.0;
break;
case "B+":
gradeInt = 3.5;
break;
case "B":
gradeInt = 3.0;
break;
case "C+":
gradeInt = 2.5;
break;
case "C":
gradeInt = 2.0;
break;
case "D+":
gradeInt = 1.5;
break;
case "D":
gradeInt = 1.0;
break;
case "F":
gradeInt = 0.0;
break;
}
return gradeInt;
}
}
package org.example.grade.domain;
import java.util.List;
/**
* Course 객체의 컬렉션을 관리하는 일급 컬렉션 클래스입니다.
* 이 클래스는 여러 Course 객체를 하나의 컬렉션으로 관리하며,
* 총합 계산과 같은 연산을 수행하는 메서드를 제공합니다.
*/
public class Courses {
private final List<Course> courses;
/**
* Courses 클래스 생성자.
*
* @param courses Course 객체의 리스트입니다.
*/
public Courses(List<Course> courses){
this.courses = courses;
}
/**
* 모든 과목의 학점과 점수의 곱의 합을 계산합니다.
*
* @return 학점수와 교과목 평점의 곱의 총합입니다.
*/
public double multiplyCreditAndCourseGrade(){
return courses.stream()
.mapToDouble(Course::multiplyCreditAndCourseGrade)
.sum();
}
/**
* 총 이수한 학점을 계산합니다.
*
* @return 총 이수한 학점입니다.
*/
// 총 이수한 학점
public int calculateTotalCompletedCredit(){
return courses.stream()
.mapToInt(Course::getCredit)
.sum();
}
}
package org.example.grade.domain;
/**
* 학점 계산기 클래스입니다.
* 이 클래스는 Courses 객체를 받아 평균 학점을 계산하는 기능을 수행합니다.
*/
public class GradeCalculator {
private final Courses courses;
/**
* GradeCalculator 클래스 생성자.
*
* @param courses 학점 계산에 사용될 Courses 객체입니다.
*/
public GradeCalculator(Courses courses){
this.courses = courses;
}
/**
* 평균학점을 계산합니다.
*
* @return 계산된 평균학점과 총 이수한 학점을 담은 GradeResult 객체입니다.
*/
public GradeResult calculateGrade(){
double totalMultipliedCreditAndCourseGrade = courses.multiplyCreditAndCourseGrade();
int totalCompletedCredit = courses.calculateTotalCompletedCredit();
double averageGrade = totalMultipliedCreditAndCourseGrade / totalCompletedCredit;
return new GradeResult(averageGrade, totalCompletedCredit);
}
}
package org.example.grade.domain;
/**
* 학점 계산 결과를 나타내는 클래스입니다.
* 평균 학점과 총 이수한 학점 정보를 제공합니다.
*/
public class GradeResult {
final private double averageGrade;
final private int totalCompletedCredit;
/**
* GradeResult 클래스 생성자.
*
* @param averageGrade 계산된 평균 학점입니다.
* @param totalCompletedCredit 총 이수한 학점입니다.
*/
public GradeResult(double averageGrade, int totalCompletedCredit){
this.averageGrade = averageGrade;
this.totalCompletedCredit = totalCompletedCredit;
}
public double getAverageGrade(){
return averageGrade;
}
public int getTotalCompletedCredit(){
return totalCompletedCredit;
}
}
코드 설명
위 Java 코드는 학점 계산기 시스템을 구현한 것입니다. 이 시스템은 학생들이 수강한 과목의 학점과 점수를 바탕으로 평균 학점을 계산합니다. 코드는 도메인 중심 설계를 따르며, Course, Courses, GradeCalculator, GradeResult 클래스로 구성되어 있습니다. 각 클래스의 역할은 다음과 같습니다:
Course 클래스
- 과목을 나타내며, 과목명(
subject), 학점(credit), 점수(grade)를 속성으로 가집니다. MAJOR_CREDIT과GENERAL_CREDIT상수는 전공과 일반 과목의 학점을 나타냅니다.multiplyCreditAndCourseGrade()메서드는 과목의 학점과 점수를 숫자로 변환한 값을 곱합니다.getGradeToNumber()메서드는 문자열로 된 점수를 숫자로 변환하여 반환합니다.
Courses 클래스 (일급 컬렉션)
- 여러
Course객체를 하나의 컬렉션(List<Course>)으로 관리합니다. multiplyCreditAndCourseGrade()메서드는 모든 과목의 학점과 점수의 곱의 합을 계산합니다.calculateTotalCompletedCredit()메서드는 총 이수한 학점을 계산합니다.
GradeCalculator 클래스
- 학점 계산을 담당합니다.
Courses객체를 받아 생성되며, 평균 학점을 계산하는calculateGrade()메서드를 제공합니다.- 평균 학점은 모든 과목의 학점과 점수의 곱의 합을 총 이수한 학점으로 나눈 값입니다.
- 계산 결과는
GradeResult객체로 반환됩니다.
GradeResult 클래스
- 계산된 평균 학점(
averageGrade)과 총 이수한 학점(totalCompletedCredit)을 저장합니다. - 계산 결과를 조회할 수 있는 getter 메서드(
getAverageGrade(),getTotalCompletedCredit())를 제공합니다.
테스트 코드 (GradeCalculatorTest 클래스)
GradeCalculator의 기능을 테스트합니다.- 학점 계산기에 여러 과목(
Course객체)을 입력하여 평균 학점이 올바르게 계산되는지 확인합니다. @Test어노테이션이 사용된calculateGradeTest()메서드에서 실제 계산을 수행하고, 결과를 콘솔에 출력합니다.
전체적으로, 이 코드는 객체지향 원칙을 잘 따르며, 각 클래스가 단일 책임을 가지고 있습니다. Course는 과목 정보를, Courses는 과목 리스트를, GradeCalculator는 학점 계산 로직을, 그리고 GradeResult는 계산 결과를 책임집니다. 이를 통해 재사용성과 유지보수성이 높은 코드 구조를 갖추고 있습니다.
Python으로 코드 구현
파이썬으로 학점 계산기 시스템을 구현해보겠습니다. 파이썬은 Java와 달리 인터페이스와 추상 클래스에 대한 엄격한 요구사항이 없으며, 더 동적인 언어 특성을 가지고 있습니다. 여기서는 클래스를 정의하고, 각 클래스에 해당하는 기능을 구현하여 Java 코드의 기능을 재현합니다.
from typing import List
class Course:
MAJOR_CREDIT = 3
GENERAL_CREDIT = 2
def __init__(self, subject: str, credit: int, grade: str):
self.subject = subject
self.credit = credit
self.grade = grade
def multiply_credit_and_course_grade(self) -> float:
return self.credit * self.get_grade_to_number()
def get_grade_to_number(self) -> float:
grade_to_number = {
"A+": 4.5, "A": 4.0, "B+": 3.5, "B": 3.0,
"C+": 2.5, "C": 2.0, "D+": 1.5, "D": 1.0, "F": 0.0,
}
return grade_to_number.get(self.grade, 0.0)
class Courses:
def __init__(self, courses: List[Course]):
self.courses = courses
def multiply_credit_and_course_grade(self) -> float:
return sum(course.multiply_credit_and_course_grade() for course in self.courses)
def calculate_total_completed_credit(self) -> int:
return sum(course.credit for course in self.courses)
class GradeResult:
def __init__(self, average_grade: float, total_completed_credit: int):
self.average_grade = average_grade
self.total_completed_credit = total_completed_credit
def __str__(self):
return f"이번 학기 학점: {self.average_grade:.2f} (총 {self.total_completed_credit}학점)"
class GradeCalculator:
def __init__(self, courses: Courses):
self.courses = courses
def calculate_grade(self) -> GradeResult:
total_multiplied_credit_and_course_grade = self.courses.multiply_credit_and_course_grade()
total_completed_credit = self.courses.calculate_total_completed_credit()
average_grade = total_multiplied_credit_and_course_grade / total_completed_credit
return GradeResult(average_grade, total_completed_credit)
def main():
courses = Courses([
Course("OOP", Course.MAJOR_CREDIT, "A+"),
Course("자료구조", Course.MAJOR_CREDIT, "A+"),
Course("중국어회화", Course.GENERAL_CREDIT, "C")
])
grade_calculator = GradeCalculator(courses)
grade_result = grade_calculator.calculate_grade()
print(grade_result)
if __name__ == "__main__":
main()
이 파이썬 구현에서는 Java 버전과 유사하게 학점 계산 로직을 구현했습니다. Course 클래스는 개별 과목을, Courses는 과목의 컬렉션을, GradeCalculator는 평균 학점 계산을, 그리고 GradeResult는 계산 결과를 나타냅니다. main.py에서는 실제로 이 모든 클래스를 사용하여 학점 계산을 수행하고 결과를 출력합니다.