You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
악덕 기획자 : 서비스 오픈 직전에 할인 정책을 고정 금액 할인이 아닌 좀 더 합리적인 주문 금액 당 할인하는 정률 % 할인으로 변경하고 싶어요.
ex) 기존에는 VIP가 주문하는 금액에 상관없이 1000원을 할인하였는데 새로 나온 정책으로 10000원 주문 시 1000원을 할인해주고, 20000원 주문 시 2000원을 할인해주고 싶어요. 순진 개발자 : 처음부터 고정 금액 할인은 아니라고 했잖아요. 악덕 기획자 : 애자일 소프트에어 개발 선언 모르시나요? "계획을 따르기보다 변화에 대응하기를" 순진 개발자 : 하지만 유연한 설계가 가능하도록 객체 지향 설계 원칙을 준수하였기에 쉽지 않을까?
publicclassOrderServiceImplimplementsOrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();privatefinalDiscountPolicydiscountPolicy = newRateDiscountPolicy();
}
문제점 발견
✔️ 우리는 역할과 구현을 충실하게 분리했다.
✔️ 다형성도 활용하고, 인터페이스와 구현 객체를 분리했다.
❌ OPC,DIP 같은 객체지향 설계 원칙을 준수한 것 같아보이지만 아니다.
❌ DIP: 주문서비스 클라이언트(OrderServiceImpl) 는 DiscountPolicy 인터페이스에 의존하면서 DIP를 지킨 것 같지만, 추상 (인터페이스) 뿐만 아니라 구체(구현) 클래스에도 의존 하고 있다.
❌ 지금 코드는 기능을 확장해서 변경하면 클라이언트 코드에 영향을 준다. 따라서 OCP를 위반한다.
기대했던 의존 관계
실제 의존 관계
지금까지 단순히 DiscountPolicy 인터페이스만 의존한다고 생각했지만, 클라이언트인 OrderServiceImpl 이 DiscountPolicy 인터페이스 뿐만 아니라 FixDiscountPolicy 인 구체 클래스도 함께 의존 하고 있다.
❗ DIP 위반이다.
정책 변경
⭐ 그래서 FixDiscountPloicy 를 RateDiscountPolicy 로 변경하는 순간 OrderServiceImpl 소스코드도 함께 변경해야한다. --> OCP 위반
따라서 인터페이스에만 의존하도록 설계를 변경해야한다.
publicclassOrderServiceImplimplementsOrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();privateDiscountPolicydiscountPolicy;
}
이 코드의 문제점 : DIP는 지켰지만, 객체가 없어 돌아가지 않는다. 즉 널 포인터 예외가 발생한다.
❗ 해결 방안 : 누군가가 클라이언트인 OrderServiceImpl 에 DiscountPolicy 의 구현 객체를 대신 생성하고 주입해줘야한다.
관심사의 분리
애플리케이션을 하나의 공연이라고 생각하자. 각각 인터페이스를 배역(배우 역할)이라 생각하자. 그 때 실제 배역 맞는 배우를 선택하는 것은 누구의 역할인가?
로미오와 줄리엣 공연이라고 할 때 누가 로미오, 줄리엣 역할을 할 것인지를 배우가 정하는 것이 아니다. 이 전에 구현했던 코드는 레오나르도 디카프리오가 공연도 해야하고 동시에 여자 주인공도 직접 초빙해야 하는 것과 같다. --> 다양한 책임 을 가지고 있다.
이 때 필요한 것이 관심사의 분리이다
AppConfig 등장
애플리케이션의 전체 동작 방식을 구성하기 위해, 구현 객체를 생성 하고, 연결 하는 책임을 가지는 별도의 설정 클래스를 만들어야한다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
새로운 할인 정책 개발
새로운 할인 정책을 확장해보자
📌 참고 : 애자일 소프트웨어 개발 선언 https://agilemanifesto.org/iso/ko/manifesto.html
RateDiscountPolicy 추가
DiscountPolicy아래에RateDiscountPolicy구현을 추가하였다.RateDiscountPolicy코드 추가테스트 작성
test/RateDiscountPolicyTest새로운 할인 정책 적용과 문제점
방금 추가한 할인 정책을 적용
OrderServiceImpl코드를 고쳐야한다.문제점 발견
✔️ 우리는 역할과 구현을 충실하게 분리했다.
✔️ 다형성도 활용하고, 인터페이스와 구현 객체를 분리했다.
❌ OPC,DIP 같은 객체지향 설계 원칙을 준수한 것 같아보이지만 아니다.
❌ DIP: 주문서비스 클라이언트
(OrderServiceImpl)는DiscountPolicy인터페이스에 의존하면서 DIP를 지킨 것 같지만, 추상 (인터페이스) 뿐만 아니라 구체(구현) 클래스에도 의존 하고 있다.❌ 지금 코드는 기능을 확장해서 변경하면 클라이언트 코드에 영향을 준다. 따라서 OCP를 위반한다.
⭐ 그래서
FixDiscountPloicy를RateDiscountPolicy로 변경하는 순간OrderServiceImpl소스코드도 함께 변경해야한다. --> OCP 위반따라서 인터페이스에만 의존하도록 설계를 변경해야한다.
관심사의 분리
AppConfig 등장
애플리케이션의 전체 동작 방식을 구성하기 위해, 구현 객체를 생성 하고, 연결 하는 책임을 가지는 별도의 설정 클래스를 만들어야한다.
AppConfigAppConfig는 애플리케이션의 실제 동작에 필요한 구현 객체를 생성 한다.MemberServiceImplMemoryMemberRepositoryOrderServiceImplFixDiscountPolicyAppConfig는 생성한 객체 인스턴스의 참조 (레퍼런스)를 생성자를 통해서 주입(연결) 해준다.MemberServiceImple->MemoryMemberRepositoryOrderServiceImpl->MemoryMemberRepository,FixDiscountPolicy📌 지금은 각 클래스에 생성자가 없어 컴파일 오류 발생. 바로 다음 코드에 이어서 생성자 생성
MemberServiceImpl - 생성자 주입
클래스 다이어그램
회원 객체 인스턴스 다이어그램
OrderServiceImpl- 생성자 주입AppConfig 실행
MemberAppOrderAppMemberServiceTestOrderServiceTest📌 정리
AppConfig를 통해서 관심사를 확실하게 분리했다.AppConfig는 구체 클래스를 선택한다. 즉, 애플리케이션이 어떻게 동작해야 할 지 전체 구성을 책임진다.OrderServiceImpl은 기능을 실행하는 책임만 지면 된다.AppConfig 리팩터링
새로운 구조와 할인 정책 적용
정액 할인 정책을 정률 할인 정책으로 변경하자
AppConfig 의 등장으로 애플리케이션이 크게 사용 영역과, 객체를 생성하고 구성하는 영역으로 분리되었다.
그림 - 사용, 구성의 분리

그림 - 할인 정책의 변경

All reactions