학점계산기
구현에 앞서 필요한 과정들을 서술하면 다음과 같습니다:
구현 하기 전 생각하기
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
에서는 실제로 이 모든 클래스를 사용하여 학점 계산을 수행하고 결과를 출력합니다.