공부내용 정리/자바

객체지향 패러다임 3 (학점계산기)

minsoku 2023. 9. 5. 16:33

 

객체지향 이해 세번째 학점 계산기 만들기입니다.

 

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;
    }
}

- 일급컬렉션을 사용하여 계산을 위임합니다.