#3 ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ์กด์ ๋ถํธํ ์ค๊ณ ๋ฐฉ์
by JiwonDevํด๋น ๊ธ์ ๊น์ํ๋์ ์ธํ๋ฐ ๊ฐ์๋ฅผ ๊ณต๋ถํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
๊น์ํ ์ ๊ฒ์ ๊ฒฐ๊ณผ - ์ธํ๋ฐ | ๊ฐ์
๊ด์ฌ ์๋ ๊ฐ์๊ฐ ์๋ค๋ฉด ์ง๊ธ ๋น์ฅ ์์ํ์ธ์! ์ธํ๋ฐ์ ์ธ์ ๋ ๋น์ ์ ์ฑ์ฅ์ ์์ํฉ๋๋ค. - ํ์ตํ๊ธฐ | ์ธํ๋ฐ...
www.inflearn.com
์คํ๋ง ์์ด ์์ํ ์๋ฐ์ฝ๋๋ก ๋น์ฆ๋์ค ์๋น์ค๋ฅผ ๋ง๋ค์ด๋ณด์.
# ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ
๋ค์๊ณผ ๊ฐ์ ๊ธฐํ์์ ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ์ด ์๋ค๊ณ ๊ฐ์ ํด๋ณด์. ์๊ตฌ์ฌํญ ์ค์๋ ์์ง ํ์ ๋์ง ์์๊ฑฐ๋, ๊ฐ๋ฐ ๋์ค ๋ณ๊ฒฝํ ์๋ ์๋ ๋ด์ฉ๋ค์ด ํฌํจ๋์ด ์๋ค.

# ํ์
# ํ์ ๋๋ฉ์ธ ์ค๊ณ
์ฐ์ , ๋น์ฆ๋์ค์ ํต์ฌ์ธ ํ์์ ๋๋ฉ์ธ์ ๋ํด ์ค๊ณ๋ฅผ ์์ํด๋ณด์.
๋๋ฉ์ธ์ด ๋ญ์ฃ
ํด๊ฒฐํ๊ณ ์ ํ๋ ๋ฌธ์ ๋ฐ ๊ด์ฌ์ฌ๋ฅผ ๋๋ฉ์ธ(Domain)์ด๋ผ๊ณ ํํํ๋ค. ์๋ฅผ ๋ค์ด ์์ ์๋น์ค๋ฅผ ๋ง๋ค๊ณ ์ ํ๋ค๋ฉด, ๋๋ฉ์ธ์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑํ ์ ์๋ค.

์ด๋ ๊ฒ ๋ง๋ ๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ฐํ์ผ๋ก ๊ตฌ์ฒดํํ์ฌ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ๊ณผ ๊ฐ์ฒด ๋ค์ด์ด๊ทธ๋จ์ ๋ง๋ ๋ค.

ํ์ฌ ์ฃผ์ด์ง ํ์ ๋๋ฉ์ธ์ ์๊ตฌ์ฌํญ์ ์๋์ ๊ฐ๋ค.
- ํ์์ ๊ฐ์
ํ๊ณ ์กฐํํ ์ ์๋ค
โ ํ์๊ฐ์ ๊ณผ ์กฐํ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ [ํ์ ์๋น์ค] ๋ฅผ ๋ง๋ ๋ค. - ํ์์ ์ผ๋ฐ๊ณผ VIP ๋ ๊ฐ์ง ๋ฑ๊ธ์ด ์๋ค.
โ ํ์ ๋๋ฉ์ธ์ ๋ฑ๊ธ ์ ๋ณด๋ฅผ ๊ฐ์ง๋ค. Enum ์ ์ด์ฉํ์ฌ ๋ฑ๊ธ์ ๋ํ๋ด๋ ํ์ ์ ๋ง๋ ๋ค. - ํ์ ๋ฐ์ดํฐ ์์ฒด DB๋ฅผ ๊ตฌ์ถํ ์ ์๊ณ , ์ธ๋ถ ์์คํ
๊ณผ ์ฐ๋ํ ์ ์๋ค.(๋ฏธํ์ )
โ ํ์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ์ญํ , [ํ์ ์ ์ฅ์] ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ ๋ค.

์ด๋ ๊ฒ ๋ง๋ ๋๋ฉ์ธ์ ์ด์ฉํ์ฌ ๊ฐ์ฒด & ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ๋ง๋ค์ด๋ณด์.
- [ํ์ ์๋น์ค]๋ MemberService ์ธํฐํ์ด์ค(์ญํ )์ ๋ง๋ค๊ณ MemberServiceImpl๋ก ๊ตฌํํ๋ค.
- [ํ์ ์ ์ฅ์]๋ MemberRepository ์ธํฐํ์ด์ค(์ญํ )์ ๋ง๋ค๊ณ ๊ฐ ์ ์ฅ์๋ณ ๊ตฌํ์ฒด๋ฅผ ๊ตฌํํ๋ค.

๋๋ฉ์ธ๊ณผ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ด ์์ฑ๋์๋ค๋ฉด, ์ค์ ์๋ฒ์์ ๊ฐ์ฒด๊ฐ ์ฐธ์กฐ๊ฐ ์ด๋ป๊ฒ ๋๋์ง๋ฅผ ๊ทธ๋ฆฐ๋ค. ์ด๋ฅผ ๊ฐ์ฒด ๋ค์ด์ด๊ทธ๋จ์ด๋ผ ํ๋ฉฐ ์ค์ ์๋น์ค๊ฐ ์ด๋ป๊ฒ ๋์ ๋๋์ง ํ๋์ ๋ณผ ์ ์๋ค.
- ํด๋ผ์ด์ธํธ๋ ํ์์๋น์ค๋ฅผ ํธ์ถํ๊ณ , ํ์ ์๋น์ค๋ ํ์ ์ ์ฅ์๋ฅผ ์ฐธ์กฐํ์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ์คํํฉ๋๋ค.

์ด๋ฅผ ๋ฐํ์ผ๋ก ์ง์ ์์ฑํ ์๋ฐ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ๋๋ฉ์ธ (Member, Grade)
public enum Grade { BASIC, VIP }
public class Member { private Long id; private String name; private Grade grade; public Member(Long id, String name, Grade grade) { this.id = id; this.name = name; this.grade = grade; } // ... getter setter ์๋ต ... }
- ์๋น์ค (MemberService, MemberServiceImpl)
public interface MemberService { void join(Member member); Member findMember(Long memberId); }
public class MemberServiceImpl implements MemberService { public final MemberRepository memberRepository = new MemoryMemberRepository(); @Override public void join(Member member) { memberRepository.save(member); } @Override public Member findMember(Long memberId) { return memberRepository.findById(memberId); } }
- ์ ์ฅ์ (MemberRepository, MemoryMemberRepository)
public interface MemberRepository { void save(Member member); Member findById(Long memberId); }
public class MemoryMemberRepository implements MemberRepository { public static Map<Long, Member> store = new HashMap<>(); @Override public void save(Member member) { store.put(member.getId(), member); } @Override public Member findById(Long memberId) { return store.get(memberId); } }
# ํ์ ๋๋ฉ์ธ ์คํ๊ณผ ํ ์คํธ
์์ฑํ ์ฝ๋๋ค์ด ์ ์๋ํ๋์ง ์๋น์ค ๊ณ์ธต๋ถํฐ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํด์ ํ์ธํด๋ณด์.
import hello.core.member.Grade; import hello.core.member.Member; import hello.core.member.MemberService; import hello.core.member.MemberServiceImpl; // ์ฑ ์ง์
์ public class MemberApp { public static void main(String[] args) { MemberService memberService = new MemberServiceImpl(); Member member = new Member(1L, "memberA", Grade.VIP); memberService.join(member); Member findMember = memberService.findMember(1L); System.out.println("new member = " + member.getName()); System.out.println("findMember = " + findMember.getName()); } }
import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; // JUnit์ ์ด์ฉํ ํ
์คํธ class MemberServiceTest { MemberService memberService = new MemberServiceImpl(); @Test void join() { //given Member member = new Member(1L, "memberA", Grade.VIP); //when memberService.join(member); Member findMember = memberService.findMember(1L); //then Assertions.assertThat(member).isEqualTo(findMember); } }
# ํ์ ๋๋ฉ์ธ ํ๊ฐํ๊ธฐ
ํ์ ๋๋ฉ์ธ์ ์ค๊ณ์ ํ ์คํธ๋ฅผ ์ฑ๊ณตํ๋ค. ์ ๊ทธ๋ ๋ค๋ฉด ํด๋น ์ฝ๋๋ ๊ฐ์ฒด์งํฅ์์ ๋งํ๋ SOLID ์์น์ OCP, DIP๋ฅผ ๋ง์กฑํ๊ณ ์๋๊ฐ? ๋คํ์ฑ์ด ์ ์ค๊ณ๋ ์ฝ๋์ผ๊น?
- ํ์ ์ ์ฅ์๋ก MemberRepository๋ฅผ ์ฌ์ฉํ ๋ ๋์ค์ ์ ์ฅ์๋ฅผ ๋ณ๊ฒฝํ ๋ OCP ์์น์ด ์ง์ผ์ง ์ ์๋๊ฐ?
- DIP๊ฐ ์ ์ง์ผ์ง๊ณ ์๋๊ฐ?
์๋๋ค. ์์กด๊ด๊ณ๊ฐ ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด์ ๋ชจ๋ ์๋ค. ์ผ๋จ์ ๋์ด๊ฐ๋๋ก ํ๊ณ , ์ฃผ๋ฌธ๊ณผ ํ ์ธ์ ์ค๊ณํด๋ณด์.

# ์ฃผ๋ฌธ๊ณผ ํ ์ธ
# ์ฃผ๋ฌธ๊ณผ ํ ์ธ ๋๋ฉ์ธ ์ค๊ณ
- ํ์์ ์ํ์ ์ฃผ๋ฌธํ ์ ์๋ค.
- ํ ์ธ ์ ์ฑ ์ ๋ชจ๋ VIP๋ 1000์์ ํ ์ธํด์ฃผ๋ ๊ณ ์ ๊ธ์ก ํ ์ธ์ ์ ์ฉํด๋ฌ๋ผ.(๋ณ๊ฒฝ๊ฐ๋ฅ)
- ํ ์ธ ์ ์ฑ
์ ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ด ๋๋ค. ํ์ฌ์ ๊ธฐ๋ณธ ํ ์ธ ์ ์ฑ
์ ์์ง ์ ํ์ง ๋ชปํ๋ค.
์คํ ์ง์ ๊น์ง ๊ณ ๋ฏผ์ ๋ฏธ๋ฃจ๊ณ ์ถ๋ค. ์ต์ ์ ๊ฒฝ์ฐ ํ ์ธ์ ์ ์ฉํ์ง ์์ ์ ์๋ค. (๋ฏธํ์ )
์ฃผ๋ฌธ๊ณผ ํ ์ธ์ ๋ํ ์ ์ฑ ๊ณผ ์๊ตฌ์ฌํญ์ ๋ถ์ํด๋ณด์. ํ์์ ์ฃผ๋ฌธ์ ํ ์ ์๋๋ฐ, ํ์์ ๋ฑ๊ธ์ ๋ฐ๋ผ ์ํ์ ํ ์ธ์ด ์ ์ฉ๋ ์ ์๋ค. ์ด๋ฅผ ์ ๋ฆฌํ๋ฉด ์๋ 4๊ฐ์ง๋ก ๋ง๋ค ์ ์๋ค.
- ์ฃผ๋ฌธ ์์ฑ: ํด๋ผ์ด์ธํธ๋ ์ฃผ๋ฌธ ์๋น์ค์ ์ฃผ๋ฌธ ์์ฑ์ ์์ฒญํ๋ค.
- ํ์ ์กฐํ: ํ ์ธ์ ์ํด์ ํ์ ๋ฑ๊ธ์ ์์์ผํ๊ธฐ์ ํ์์ ์กฐํํ๋ค.
- ํ ์ธ ์ ์ฉ: ํ์ ๋ฑ๊ธ์ ๋ฐ๋ฅธ ํ ์ธ์ฌ๋ถ์ ํ ์ธ ๊ธ์ก์ ์๊ธฐ ์ํด ํด๋น ์ฑ ์์ ํ ์ธ ์ ์ฑ ์ญํ ์ ์์ํ๋ค.
- ์ฃผ๋ฌธ ๊ฒฐ๊ณผ ๋ฐํ: ์ฃผ๋ฌธ ์๋น์ค๋ ํ ์ธ ๊ฒฐ๊ณผ๋ฅผ ํฌํจํ ์ฃผ๋ฌธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค.

๋ง๋ค์ด๋ ผ ์ค๊ณ๋ฅผ ๋ฐํ์ผ๋ก ํด๋์ค์ ๊ตฌ์ฑ๋๋ฅผ ๊ทธ๋ ค๋ณด์. ๊ฐ์ฒด๋ฅผ ์ง์ ์ฐ๊ฒฐํ๋๊ฒ ์๋ ์ญํ (์ธํฐํ์ด์ค)์ ๊ตฌํ(๊ฐ์ฒด)๋ฅผ ๋ถ๋ฆฌํ๋ค. ์ด๋ ๊ฒ "์ญํ ๊ณผ ๊ตฌํ์ ๋ถ๋ฆฌ"ํด์ ์ค๊ณํ์ฌ์ผ [ํ์ ์ ์ฅ์]๋ [ํ ์ธ ์ ์ฑ ]์ ์ ์ฐํ๊ฒ ๋ณ๊ฒฝํ ์ ์๋ค.

๋๋ฉ์ธ๊ณผ ํด๋์ค๋ฅผ ๋ฐํ์ผ๋ก ๊ฐ์ฒด๊ฐ์ ์ฐธ์กฐ ๊ด๊ณ๋ฅผ ๊ทธ๋ฆฐ๋ค.

์ฃผ๋ฌธ๊ณผ ํ ์ธ์ ์ฑ ์ ๊ด๋ จํ์ฌ ๋๋ฉ์ธ๊ณผ ์ญํ (์ธํฐํ์ด์ค)์ ์ฐจ๋ก๋๋ก ์์ฑํด๋ณด์. ์ค์ ์ค๊ณ์์๋ '์ํ'๋ ๋๋ฉ์ธ์ผ๋ก ๋ง๋ค์ด ๊ฐ์ฒด ์ค๊ณ๋ฅผ ํด์ผํ์ง๋ง ์ด๋ฒ ์์ ์์๋ ๊ฐ๋จํ๊ฒ ์ํ์ ์ด๋ฆ๊ณผ ๊ฐ๊ฒฉ๋ง ๋ฐ์ดํฐ๋ก ๋ฐ๋๋ก ๋ง๋ค์๋ค.
์ฃผ๋ฌธ๋๋ฉ์ธ (Order)
package hello.core.discount; public class Order { private Long memberId; private String itemName; private int itemPrice; private int discountPrice; public Order(Long memberId, String itemName, int itemPrice, int discountPrice) { this.memberId = memberId; this.itemName = itemName; this.itemPrice = itemPrice; this.discountPrice = discountPrice; } public int calculatePrice() { return itemPrice - discountPrice; } public Long getMemberId() { return memberId; } public void setMemberId(Long memberId) { this.memberId = memberId; } public String getItemName() { return itemName; } public void setItemName(String itemName) { this.itemName = itemName; } public int getItemPrice() { return itemPrice; } public void setItemPrice(int itemPrice) { this.itemPrice = itemPrice; } public int getDiscountPrice() { return discountPrice; } public void setDiscountPrice(int discountPrice) { this.discountPrice = discountPrice; } @Override public String toString() { return "Order{" + "memberId=" + memberId + ", itemName='" + itemName + '\'' + ", itemPrice=" + itemPrice + ", discountPrice=" + discountPrice + '}'; } }
์ฃผ๋ฌธ ์๋น์ค ์ญํ , ์ธํฐํ์ด์ค(OrderService)
public interface OrderService { Order createOrder(Long memberId, String itemName, int itemPrice); }
ํ ์ธ ์ ์ฑ ์๋น์ค ์ญํ (DiscountPolicy)
public interface DiscountPolicy { /** * @return ํ ์ธ ๋์ ๊ธ์ก */ int discount(Member member, int price); }
์ธํฐํ์ด์ค ์ค๊ณ๋ฅผ ์๋ฃํ๋ค๋ฉด, ๋ฐ๋ก ์๋์ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด๋ ๋์ง๋ง, ์ ๊น ๋์ด๊ฐ์ ํ ์คํธ์ฝ๋๋ถํฐ ์์ฑํด๋ณด์. ์ด๋ ๊ฒ ํ ์คํธ ์ฝ๋๋ฅผ ๋จผ์ ์์ฑํ๋ฉด ์ด๋ค ์ด์ ์ด ์์๊น?
//DiscountPolicy ๊ตฌํ์ฒด public class FixDiscountPolicy implements DiscountPolicy{ private int discountFIxAmount = 1000; // 1000์ ํ ์ธ @Override public int discount(Member member, int price) { if (member.getGrade() == Grade.VIP) { return discountFIxAmount; } return 0; } }
//OrderSevice ๊ตฌํ์ฒด public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository = new MemoryMemberRepository(); private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); @Override public Order createOrder(Long memberId, String itemName, int itemPrice) { Member member = memberRepository.findById(memberId); int discount = discountPolicy.discount(member, itemPrice); return new Order(memberId, itemName, itemPrice, discount); } }
# ์ฃผ๋ฌธ๊ณผ ํ ์ธ ๋๋ฉ์ธ ๊ตฌํ๊ณผ ํ ์คํธ

@DisplayName("OderService ํด๋์ค์") class OrderServiceTest { private Member basicMember; private Member vipMember; private OrderService orderService; private MemberService memberService; @BeforeEach void setup() { orderService = new OrderServiceImpl(); memberService = new MemberServiceImpl(); basicMember = new Member(1L, "BASIC", Grade.BASIC); vipMember = new Member(2L, "VIP", Grade.VIP); memberService.join(basicMember); memberService.join(vipMember); } @Nested @DisplayName("createOrder ๋ฉ์๋๋") class Describe_createOrder { @Nested @DisplayName("์ผ๋ฐ ๋ฑ๊ธ์ ํ์์ด 10000์์ง๋ฆฌ ๋ฌผ๊ฑด์ ์ฃผ๋ฌธ์ ์์ฑํ ๊ฒฝ์ฐ ๊ฐ๊ฒฉ์") class Context_with_create_order_from_basic_member { @DisplayName("์ ํ์ ๋ฌผ๊ฑด ๊ฐ๊ฒฉ ๊ทธ๋๋ก ์์ฑ๋๋ค.") @Test void it_is_original_price() { //when Order order = orderService.createOrder(basicMember.getId(), "item", 10000); //then assertThat(order.calculatePrice()).isEqualTo(10000); } } @Nested @DisplayName("VIP๋ฑ๊ธ์ ํ์์ด 10000์์ง๋ฆฌ ๋ฌผ๊ฑด์ ์ฃผ๋ฌธ์ ์์ฑํ ๊ฒฝ์ฐ ๊ฐ๊ฒฉ์") class Context_with_create_order_from_vip_member { @DisplayName("์ ํ์ ๋ฌผ๊ฑด ๊ฐ๊ฒฉ ๊ทธ๋๋ก ์์ฑ๋๋ค.") @Test void it_is_discounted_price() { //when Order order = orderService.createOrder(vipMember.getId(), "item", 10000); //then assertThat(order.calculatePrice()).isEqualTo(9000); } } } }
# ์ด ์ฝ๋๋ OCP์ DIP๋ฅผ ์งํค๊ณ ์๋ ์ค๊ณ์ผ๊น?
์๋์ ๊ฐ์ด ์๋ก์ด ํ ์ธ ์ ์ฑ ์ ๋ง๋ ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
์ ๋ ๊ธฐํ์: ์๋น์ค ์คํ ์ง์ ์ ํ ์ธ ์ ์ฑ ์ ์ง๊ธ์ฒ๋ผ ๊ณ ์ ๊ธ์ก ํ ์ธ์ด ์๋๋ผ ์ข ๋ ํฉ๋ฆฌ์ ์ธ ์ฃผ๋ฌธ ๊ธ์ก ๋น ํ ์ธํ๋ ์ ๋ฅ % ํ ์ธ์ผ๋ก ๋ณ๊ฒฝํ๊ณ ์ถ์ด์.
์๋ฅผ ๋ค์ด์ ๊ธฐ์กด ์ ์ฑ ์ VIP๊ฐ 10000์์ ์ฃผ๋ฌธํ๋ 20000์์ ์ฃผ๋ฌธํ๋ ํญ์ 1000์์ ํ ์ธํ๋๋ฐ, ์ด๋ฒ์ ์๋ก ๋์จ ์ ์ฑ ์ 10%๋ก ์ง์ ํด๋๋ฉด ๊ณ ๊ฐ์ด 10000์ ์ฃผ๋ฌธ์ 1000์์ ํ ์ธํด์ฃผ๊ณ , 20000์ ์ฃผ๋ฌธ์์ 2000์์ ํ ์ธํด์ฃผ๋ ๊ฑฐ์์!
์์ง ๊ฐ๋ฐ์: ์ ๊ฐ ์ฒ์๋ถํฐ ๊ณ ์ ๊ธ์ก ํ ์ธ์ ์๋๋ผ๊ณ ํ์์์. (์ข์ง์์ ์ปค๋ฎค๋์ผ์ด์ ์ ์1)
์ ๋ ๊ธฐํ์: ์ ์์ผ ์ํํธ์จ์ด ๊ฐ๋ฐ ์ ์ธ ๋ชฐ๋ผ์? โ๊ณํ์ ๋ฐ๋ฅด๊ธฐ๋ณด๋ค ๋ณํ์ ๋์ํ๊ธฐ๋ฅผโ
์์ง ๊ฐ๋ฐ์: โฆ
์ ์์ผ ์ํํธ์จ์ด ๊ฐ๋ฐ์ด๋?
์์์ ๊ตฌํ๊ณผ ์ญํ ์ ๊ตฌ๋ถํด๋จ๊ธฐ์ ๋จ์ํ ์๊ฐํ๋ฉด ์๋์ ๊ฐ์ด ์๋ก์ด ํ ์ธ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ , ํ ์คํธ ํด๋ณธ ๋ค ์ ์ฉ์์ผ์ฃผ๋ฉด ๋๋ค. ๊ธฐ์กด์ ๊ฐ๋ฐ๋ฐฉ์๋ณด๋ค๋ ํจ์ฌ ๊ฐ๋จํ๊ธด ํ๋ค. ํ์ค๋ง ๋ฐ๊พธ๋ฉด ๋๋๊น
public class OrderServiceImpl implements OrderService { private final MemberRepository memberRepository = new MemoryMemberRepository(); // ํ ์ธ์ ์ฑ
๊ตฌํ๋ถ ๋ณ๊ฒฝ! // private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); @Override public Order createOrder(Long memberId, String itemName, int itemPrice) { Member member = memberRepository.findById(memberId); int discountPrice = discountPolicy.discount(member, itemPrice); return new Order(memberId, itemName, itemPrice, discountPrice); } }
@ ์จ๊ฒจ์ง ๋ฌธ์ ์
- ์ฐ๋ฆฌ๋ ์ญํ ๊ณผ ๊ตฌํ์ ์ถฉ์คํ๊ฒ ๋ถ๋ฆฌํ๋ค. OK
- ๋คํ์ฑ๋ ํ์ฉํ๊ณ , ์ธํฐํ์ด์ค์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ๋ถ๋ฆฌํ๋ค. OK
- OCP, DIP ๊ฐ์ ๊ฐ์ฒด์งํฅ ์ค๊ณ ์์น์ ์ถฉ์คํ ์ค์ํ๋ค..?
-> ๊ทธ๋ ๊ฒ ๋ณด์ด์ง๋ง ์ฌ์ค์ ์๋๋ค. - DIP: ์์กด์ฑ. ์ฃผ๋ฌธ ํด๋ผ๋( OrderServiceImpl )๋ DiscountPolicy ์ธํฐํ์ด์ค๋ง ์์กดํ๋ ์งํจ๊ฑฐ ์๋๊ฐ?
- ํด๋์ค๋ฅผ ๋ค์๋ณด์. ์ถ์(์ธํฐํ์ด์ค) ๋ฟ๋ง ์๋๋ผ ๊ตฌ์ฒด(๊ตฌํ) ํด๋์ค์๋ ์์กดํ๊ณ ์๋ค.
-> ์ถ์(์ธํฐํ์ด์ค) ์์กด: DiscountPolicy
-> ๊ตฌ์ฒด(๊ตฌํ) ํด๋์ค: FixDiscountPolicy , RateDiscountPolicy - OCP: ๋ณ๊ฒฝํ์ง ์๊ณ ํ์ฅํ ์ ์๊ฒ ์ค๊ณํด์ผ ํ๋ค.
์ง๊ธ ์ฝ๋๋ ๊ธฐ๋ฅ์ ํ์ฅํด์ ๋ณ๊ฒฝํ๋ฉด, ํด๋ผ์ด์ธํธ ์ฝ๋์ ์ํฅ์ ์ค๋ค! ๋ฐ๋ผ์ OCP๋ฅผ ์๋ฐํ๋ค.
๊ฒฐ๊ตญ ๊ตฌํ์ฒด ์ฝ๋๊ฐ ๋ฐ๋๋ฉด ๋ค๋ฅธ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด์ผํจ์ ๋ณํจ์๋ค. ์กฐ๊ธ ๋ ํธํด์ก์ ๋ฟ, ์ญํ ๊ณผ ๊ตฌํ์ด ๋ถ๋ฆฌ๋์ง ์์ผ๋ฉด OCP์ DIP๊ฐ์ ๊ฐ์ฒด์งํฅ ์์น์ ์งํค์ง ๋ชปํ๋ค๋ ๋ง์ด๋ค.
@ ์๋ ๊ทธ๋ฌ๋ฉด ์ด๋ป๊ฒ OCP, DIP๋ฅผ ๊ตฌํํด์?
์ ๋ง ๊ฐ๋จํ๋ค. ์ธํฐํ์ด์ค(์ญํ )์ด ์๋ ๊ตฌํ๋ถ๋ถ์ ์ฝ๋์์ ์ ๊ฑฐํ๋ฉด ๋๋ค. ๊ทธ๋ผ DIP๋ฅผ ์ฝ๊ฒ ์งํฌ ์ ์๋ค.
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); private final DiscountPolicy discountPolicy;
??????????? ๊ทธ๋ผ ๊ตฌํ์ฒด๊ฐ ์๋๋ฐ ์ด๋ป๊ฒ ์ฝ๋๋ฅผ ์คํ์์ผ์? null์ ์คํ์์ผ์?
@ ํด๊ฒฐ๋ฐฉ์
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ๋๊ตฐ๊ฐ ํด๋ผ์ด์ธํธ์ธ 'OrderServiceImpl'์ 'DiscountPolicy' ์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ๋์ ์์ฑํ๊ณ , ์ฃผ์ ํด์ฃผ๋ฉด ๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ์ด๋ค.
๊ธ์ด ๊ธธ์ด์ ธ, ๋ค์ ๊ธ์ ๊ณ์ ์ด์ด์ ์์ฑํ๊ฒ ์ต๋๋ค.
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev