[Java] 상속과 다형성

도비·2025년 7월 13일

Java

목록 보기
4/6

문제 상황

강의를 담아 가격을 계산하는 로직에서 각 유형별로 특별한 로직(프로모션)을 부여하고자 한다.

public enum LectureType {
    DevOps("DevOps"), DBMS("DBMS"), Lang("Lang"), FW("F/W"), CS("CS");
    ...
}

다음과 같이 유형은 Enum으로 구현된 상태였고, 각 로직은 모두 "할인을 적용한다"는 측면에서 같은 역할을 가졌으나 개별적인 로직이 필요했다.

유형프로모션
DevOps모든 강의 10% 할인
DBMS강의 마다 5,000원 할인
Lang2개 이상 구매 시 가장 가격이 저렴한 강의 하나 무료
F/W구매 금액이 90,000원을 넘을 경우 30,000원 할인
CS강의 3과목 이상 구매 시 강의 30% 할인

SRP와 다형성

SRP(Single Responsibility Principle)는 하나의 객체는 하나의 책임만을 가져야 한다는 의미이다. 이들은 모두 "강의"라는 틀로 묶일 뿐더러 프로모션을 적용하는 상황에서는 열거를 표현하는 Enum에게 그 책임을 지우는 것은 과도할 것이다. 하지만 만약 이들을 관련짓지 않고 다른 클래스로 두기에는 높은 연관성을 지닌다. 이와 관한 문제를 해결하기 위해 다형성의 개념을 적용해 볼 수 있다. 다형성은 하나의 형식에 다양한 구현을 대입할 수 있음을 의미하며 상속 등을 통해 구현이 가능하다. 이 경우에도 프로모션을 적용해 계산한다는 행동의 형식은 같지만 실제적인 구현은 상이한 형태를 지닌다. 이에 상속을 통해 해당 문제를 해결했다.

해결 방법

Lecture에 계산하는 로직을 두고 클래스를 상속받아 각 유형의 강의를 구현했다.

public class Lecture {
    int id;
    String name;
    LectureType type;
    int cost;
    ...
    public int calculateCost(List<Lecture> lectures) {
        return lectures.stream()
                .map(Lecture::getCost)
                .reduce(0, Integer::sum);
    }
    ...
}
public class CSLecture extends Lecture {
    public CSLecture() {
        super();
    }

    public CSLecture(int id, String name, LectureType type, int cost) {
        super(id, name, type, cost);
    }

    @Override
    public int calculateCost(List<Lecture> lectures) {
        int price = lectures.stream()
                .map(Lecture::getCost)
                .reduce(0, Integer::sum);
        if (lectures.size() >= 3) {
            return (int) (price * 0.7);
        }
        return price;
    }
}
package mission.application.domain.lecture;

import java.util.Comparator;
import java.util.List;
import mission.application.domain.Lecture;
import mission.application.domain.enums.LectureType;

public class LangLecture extends Lecture {
    public LangLecture() {
        super();
    }

    public LangLecture(int id, String name, LectureType type, int cost) {
        super(id, name, type, cost);
    }

    @Override
    public int calculateCost(List<Lecture> lectures) {
        int price = lectures.stream()
                .map(Lecture::getCost)
                .reduce(0, Integer::sum);

        if (lectures.size() >= 2) {
            price -= lectures.stream()
                    .min(Comparator.comparing(Lecture::getCost))
                    .get()
                    .getCost();
        }

        return price;
    }
}

...
사실 Enum을 지우지는 않았다. 일단 구현해두고 리팩터링하면서 지우려고 했는데 아직도 리팩터링을 못했다...

profile
문과 였던 것...

0개의 댓글