장바구니와 주문 기능에 이어, 할인 정책 기능을 추가하기로 했다.

할인 방식에는 대표적으로 정액 할인과 정률 할인이 있다.
이를 위해 할인을 추상화하고, 정액 할인과 정률 할인을 구체적으로 구현하고자 했다.
그런데 할인을 abstract class로 정의할지, interface로 정의할지 고민이 되었다.
둘 다 추상 메소드를 통해 다형성을 제공한다는 점 때문이었다.
둘의 역할이 정확히 어떻게 되는걸까?
추상 클래스는 멤버 변수와 메소드를 가질 수 있으며, 상속을 통하여 사용할 수 있다.
공통적인 기능을 갖지만 특정 기능은 구현 클래스에서 달라질 수 있다.
예를 들어, 동물을 객체로 구현할 때 추상 클래스를 사용할 수 있다.
동물 추상 클래스에는 먹기, 자지와 같은 공통적 행동을 정의할 수 있다.
그리고 동물 추상 클래스를 상속받아서 고양이 클래스를 구현하면서
채터링과 같은 특정한 행동을 추가할 수 있으며 먹고 자는 공통적 행동을 구체적으로 재정의할 수 있다.
인터페이스는 멤버 변수를 가질 수 없고, 오직 추상 메소드를 가진다. 실제 구현은 인터페이스를 구현함으로써 이루어진다.
구현한 클래스는 모두 인터페이스에서 정의했던 공통된 행동만을 하며, 구체적인 방식만 달라지게 된다.
예를 들어, 결제 방식이 있다.
결제라는 같은 동작을 하지만 신용카드, 계좌이체, 무통장입금, 페이결제 등 구체적인 방식만 달라진다.
이전 프로젝트에서 기억나는 예시로는 여러 개의 DB를 바꿔가면서 사용하는 경우가 있었다.
DBRepository를 인터페이스로 추상화하고 H2Impl, MySQLImpl 등으로 구체적인 구현체를 만들어 사용을 했다.
인터페이스에 정의된 CRUD 행위는 똑같이 이루어지며, 각 DB에 맞는 구체적인 방법만 재정의했다.
따라서 이번 할인 정책도
모두 동일한 행위를 수행하지만 구체적인 할인 방법만 달라질 뿐이므로 인터페이스를 사용하기로 결정했다.
/* 추상화 (역할, 행위) */
public interface Discount {
int getDiscountedPrice(int price);
}
/* 구현 (구체적인 방법) */
public class FixedAmountDiscount implements Discount {
private int fixedAmount;
public FixedAmountDiscount(int fixedAmount) {
this.fixedAmount = fixedAmount;
}
@Override
public int getDiscountedPrice(int price) {
return price - fixedAmount;
}
}
public class PercentageDiscount implements Discount {
private int percentage;
public PercentageDiscount(int percentage) {
this.percentage = percentage;
}
@Override
public int getDiscountedPrice(int price) {
return price - (price * percentage / 100);
}
}
'백엔드' 카테고리의 다른 글
GraphQL 커스텀 예외 처리하기 (0) | 2024.09.13 |
---|---|
활용성있는 데이터 파이프라인 구축을 위한 아이디어 (0) | 2024.08.30 |
모델링 - 다대다 관계 설계하기 (1) | 2024.08.06 |
JWT 이해하기 (0) | 2024.03.10 |
PUT vs PATCH (0) | 2024.02.25 |