Replies: 3 comments 1 reply
|
오 혜정님 개인깃허브에도 꾸준히 올리시는군요 ..! 대단하십니댜 |
1 reply
|
고생하셨습니다. 이제 스프링 시이이작! |
0 replies
|
중간중간 나오는 팁들도 꼼꼼히 정리해주셨네요!! 수고 많으셨습니다ㅎㅎ |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
새로운 할인 정책 개발
이전 예제에서는 할인 정책으로 정액 할인을 적용했는데 기획의 변경으로 정률 할인으로 바꿔야 하는 상황이 왔다.
DiscountPolicy라는 할인 정책 인터페이스를 설계하고FixDiscountPolicy가 이를 구현했기 때문에 이제 구현체인RateDiscountPolicy를 개발해 바꿔주기만 하면 된다. ➡️ 다형성OrderServiceImpl은 DiscountPolicy를 의존하고 있고 이에 대한 구현체만 바꿔주면 된다.
할인 정책에 대한 인터페이스를 정률 할인하는 방식으로 구현해준다. 객체 지향 프로그래밍의 특징 중 하나인 다형성을 확인할 수 있다.
💡tip 테스트 클래스 생성 단축키

cmd+shift+t해당 클래스에 대한 테스트 클래스를 간편하게 생성할 수 있다.
static import를 사용하면 코드를 줄일 수 있다.새로운 할인 정책 적용과 문제점
새로운 할인 정책을 적용하기 위해서는
OrderServiceImpl(클라이언트)의 코드를 직접 변경해야 한다. ➡️ OCP 위반OrderServiceImpl은 인터페이스인DiscountPolicy에만 의존하고 있는 게 아니라 구현체에도 의존하고 있다. ➡️ DIP 위반클라이언트가 인터페이스만 의존하는 그림을 기대했지만 실제 코드를 보면 인터페이스뿐만 아니라 구현체에도 의존하고 있다.
역할과 구현을 분리하고 인터페이스와 구현 객체를 분리해 다형성도 활용했지만 OCP/DIP를 위반해 객체지향 설계 원칙을 충분히 준수하지는 못했다.
📝 인터페이스에만 의존하도록 변경
인터페이스에만 의존하도록 코드를 변경했더니 당연히 구현체가 없어
Null Pointer Exception이 발생한다.🆘 누군가 대신 구현 객체를 생성하고 주입해줘야 한다.
관심사의 분리
현재 설계를 현실 세계에 비유를 해보면 한 연극 공연에서 남자 배우가 연기도 하고 상대 여자 배우를 직접 섭외해서 지정하는 기획자의 역할까지 해내고 있는 중이다. 배우는 본인의 역할인 연기만 하면 되고 배우를 섭외하고 지정하는 역할은 별도의 기획자를 만들어 책임을 확실하게 분리해야 한다.
AppConfig 생성
구현 객체를 생성하고 연결하는 책임만 가지는 별도의 설정 클래스를 만들어준다.
new키워드로 AppConfig가 생성하고 있는 객체들은 실제 동작에 필요한 구현 객체들이다.생성자 주입
- 클래스 다이어그램
AppConfig가 담당한다 ➡️ 관심사의 분리- 회원 객체 인스턴스 다이어그램
AppConfig는 객체를 생성하고 생성한 객체의 참조값을 생성자로 전달한다.DI (Dependency Injection)이라고 한다.실행 및 테스트
이제 MemberService와 OrderService의 구현체는
AppConfig를 통해 주입 받으면 된다.테스트 코드에서는 테스트마다 서로 영향을 받지 않고 독립적으로 실행되기 위해
@BeforeEach어노테이션을 활용해 매 테스트 실행 전에AppConfig를 생성해 주입받는다.AppConfig 리팩토링
현재 AppConfig의 코드를 보면 역할에 따른 구현이 잘 보이지 않고 중복되는 코드들이 존재한다.
기대하는 역할
💡tip
cmd + opt + m단축키 - 중복되는 코드를 메소드로 추출할 수 있다.리팩토링 후
새로운 구조와 할인 정책 적용
이제 새로운 할인 정책을 적용하고 싶으면 클라이언트 코드가 아닌
AppConfig의 코드만 변경해주면 된다.OrderServiceImpl (사용 영역)의 코드는 변경해줄 필요 없고 AppConfig (구성 영역)의 코드만 변경해주면 된다.
정리
정액 할인에서 정률 할인으로 할인 정책을 변경하였다. 다형성 덕분에 추가로 개발하는 것 자체에는 문제가 없다.
새로운 할인 정책을 적용하려고 하니 클라이언트의 코드를 변경해야 했고, 이는 OCP와 DIP를 위반한 것이다.
⬇️
이에 대한 해결책으로 관심사를 분리했다.
애플리케이션의 동작 방식을 구성하는 책임을 가진
AppConfig를 따로 생성해 여기에서만 객체를 생성하고 객체 간의 연결을 담당한다.이에 따라 클라이언트 객체는 이제 실행하는 역할에만 집중할 수 있다.
좋은 객체 지향 설계의 5가지 원칙 적용
해당 예제에서는 객체 지향 설계의 5가지 원칙
SOLID중SRP,OCP,DIP를 적용했음을 확인할 수 있다.SRP 단일 책임의 원칙
한 클래스는 하나의 책임만 가져야 한다.
🚫 클라이언트가 객체 생성도 하고 연결도 하고 애플리케이션 실행까지 담당해야 했음
DIP 의존 관계 역전 원칙
추상화에 의존해야지, 구체화에 의존하면 안 된다.
🚫 클라이언트는 인터페이스(추상)에도 의존했고 해당 구현체(구체화)에도 직접적으로 의존하고 있었음
AppConfig가 담당OCP 개방 폐쇄 원칙
확장에는 열려있고 변경에는 닫혀있어야 한다.
🚫 새로운 할인 정책을 적용하기 위해서는 OrderServiceImpl(클라이언트) 코드를 직접 변경해야 했음
AppConfig에서 관리하기 때문에 구현 객체를 변경하고 싶다면AppConfig의 코드만 변경해주면 됨IoC, DI, 그리고 컨테이너
제어의 역전 IoC (Inversion of Control)
클라이언트 구현 객체가 필요한 서버 구현 객체를 생성/연결/실행함
구현 객체가 프로그램의 제어 흐름을 스스로 조종 ➡️ 개발자 입장에서 자연스러운 흐름
AppConfig 등장구현 객체는 로직 실행만 담당, 프로그램 제어 흐름은
AppConfig에서 담당한다.⬇️
프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을
제어의 역전(IoC)라고 한다.- 프레임워크 그 자체가 스스로 제어 흐름의 주도권을 가짐
- 개발자가 제어 흐름의 주도권을 가짐
프레임워크와 라이브러리의 결정적인 차이는 제어 흐름의 주도권에 있다.
의존관계 주입 DI (Dependency Injection)
정적인 클래스 의존관계
위 코드만 봐도 OrderServiceImpl이 DiscountPolicy, MemberRepository에 의존하고 있음을 알 수 있다.
클래스 다이어그램만 봐서는 실제 어떤 구현 객체가 OrderServiceImpl에 주입 될지 알 수 없다.
동적인 인스턴스 객체 의존관계
애플리케이션 실행 시점에 실제 생정된 객체 인스턴스의 참조가 연결된 의존 관계
컨테이너
AppConfig처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것을 IoC 컨테이너 또는DI 컨테이너라고 함스프링으로 전환하기
지금까지의 예제에서는 순수 자바코드로만 DI를 적용했지 스프링은 사용하지 않았다.
스프링 적용하기
@Configuration설정을 구성한다는 뜻의 어노테이션@Bean스프링 컨테이너에 스프링 빈으로 등록ApplicationContext를 사용해서 스프링 컨테이너를 적용해본다.💡tip 해당 강의에서는 스프링으로 실행하면 로그가 찍힌다는데 찍히지 않는 문제 발생
SpringBoot 3.1 이상부터는 기본 로그 레벨이
INFO로 설정되어 있어 로그가 출력되지 않는다.logback.xml파일을 생성해 로그 레벨을 직접DEBUG로 지정해주면 로그 확인 가능!김영한 강사님 답변 참고
를 찾았는데 알고보니 강의록 마지막에 있었네요 .. ㅎㅎ..스프링 컨테이너
ApplicationContext@Configuration이 붙은AppConfig를 구성 정보로 사용@Bean으로 등록한 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록 ➡️ 등록된 객체를스프링 빈이라고 함@Bean이 붙은메서드 명을스프링 빈의 이름으로 사용 (따로 바꿀 수는 있지만 웬만하면 디폴트를 따르자)스프링 빈은applicationContext.getBean()을 사용해서 찾을 수 있음기존 개발자가 직접
AppConfig를 사용해 필요한 객체 조회스프링 사용
스프링 컨테이너를 통해스프링 빈(객체)조회All reactions