-
섹션 1. 객체 지향 설계와 스프링
-
스프링을 왜 만들었을까?
자바 언어 기반의 프레임워크
= 객체지향언어의 특성을 살려내는 프레임워크
-
좋은 객체지향 프로그래밍
- 객체지향 특징 : 추상화, 캡슐화, 상속, 다형
- 컴포넌트를 쉽고 유연하게 변경하면서 개발하는 방법 → 다형성
- 역할과 구현 → 클라이언트에 영향을 주지 않고(클라이언트는 인터페이스만 알면 됨, 내부 구조 몰라도 됨) 새로운 기능 제공 가능
- 역할 = 인터페이스 / 구현 = 구현 클래스, 객체
- 스프링은 다형성 극대화
-
좋은 객체지향 설계의 5가지 원칙(SOLID)
- SRP (Single responsibility principle) : 한 클래스는 하나의 책임만(변경)
- OCP (Open/closed principle) : 확장에는 열려있으나, 변경에는 닫혀있게 → 다형성 활용 / 인터페이스 구현한 새로운 클래스 만들어서 새로운 기능 구현 (OCP는 지킬 수 없음ㅜㅜ → 스프링 컨테이너, DI 등 필요)
- LSP (Liskov substitution principle / 리스코프 치환 원칙) : 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 됨
- ISP (Interface segregation principle) : 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다!
- DIP (Dependency inversion principle / 의존관계 역전 원칙) : 인터페이스에 의존, 구현 클래스 의존 X
- 다형성 만으로는 OCP, DIP 지킬 수 X
-
-
섹션 2. 스프링 핵심 원리 이해1 - 예제 만들기
회원 서비스: MemberServiceImpl
-
섹션 3. 스프링 핵심 원리 이해2 - 객체 지향 원리 적용
-
ctrl + shift + T : Test 만들어주기!
-
문제점
- 할인 정책을 변경 시 클라이언트인 OrderServiceImpl 코드 수정 필요 private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
- DIP 위반 : OrderServiceImpl는 추상 클래스 뿐 아니라 구현 클래스도! 의존
- OCP 위반 : OrderServiceImpl 코드를 변경하는 순간 위반
-
해결방안
- DIP를 위반하지 않도록 인터페이스에만 의존하도록 의존관계를 변경 필요
- 누군가가 클라이언트인 OrderServiceImpl 에 DiscountPolicy 의 구현 객체를 대신 생성하고 주입해주어야 한다
-
관심사의 분리!
★AppConfig 등장★
-
AppConfig 리팩토링
역할과 구현 한번에 볼 수 있게
ex)
public MemberService memberService(){
return new MemberServiceImpl(*memberRepository*());
}
private static MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
-
구성 영역의 코드는 수정하되, 사용자 영역은 건들지 않고 개발 가능
-
IoC, DI, 컨테이너
- 제어의 역전 IoC(Inversion of Control) : 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것
- 의존관계 주입 DI (Dependency Injection) : 애플리케이션 실행 시점(런타임)에 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결되는 것 (동적인 객체 인스턴스 관계)
- 의존관계 주입 사용시 이점
- 클라이언트 코드를 변경하지 않고, 클라이언트가 호출하는 대상의 타입 인스턴스를 변 경 가능
- 정적인 클래스 의존관계를 변경하지 않고, 동적인 객체 인스턴스 의존관계를 쉽게 변경가
- 의존관계 역전을 시켜주는 것 = “IoC 컨테이너” 또는 “DI 컨테이너”
-
스프링으로 전환하기~
@Configuration 이 붙으면 설정(구성)정보로 사용
@Bean : 스프링 컨테이너에 등
applicationContext.getBean(name : ”memberService”, MemberService.class); : name이랑 같은 이름의 메소드를 찾을거야! 타입은 MemberService!
-
-
섹션 4. 스프링 컨테이너와 스프링 빈
-
섹션 5. 싱글톤 컨테이너
-
웹 애플리케이션과 싱글톤
여러명의 클라이언트가 동시에 서비스 요청 시 문제점 : 여러개의 객체가 생성 → 요청이 올 때마다 객체 생성 → 메모리 낭비 심함
∴ 해당 객체가 딱 1개 생성되고, 공유하도록 설계 → 싱클톤 패턴
-
싱글톤 패턴
- 정의 : 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
- private 생성자를 사용해서 외부에서 임의로 new 키워드를 사용하지 못하게!
- 방법
-
static 영역에 객체 instance를 미리 하나 생성해서 올려둔다.
- ex) private static final SingletonService instance = new SingletonService();
-
이 객체 인스턴스가 필요하면 오직 getInstance() 메서드를 통해서만 조회할 수 있다. 이 메서드를 호 출하면 항상 같은 인스턴스를 반환한다.
-
ex) public static SingletonService getInstance() {
return *instance*;
}
-
-
딱 1개의 객체 인스턴스만 존재해야 하므로, 생성자를 private으로 막아서 혹시라도 외부에서 new 키워드로 객체 인스턴스가 생성되는 것을 막는다.
- ex) private SingletonService(){}
-
-
싱글톤 컨테이너(스프링 컨테이너)
스프링 컨테이너 : 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤(1개만 생성)으로 관리
-
싱글톤 방식의 주의점
싱글톤 객체는 상태를 유지하게 설계하면 안된다!
**※**사용자A 1만원 주문하고 사용자B 2만원 주문하면 사용자A 주문가격이 2만원으로?!!! 되는 문제
∴ price 필드는 공유되는 필드인데 특정 클라이언트가 값을 변경한다 → 스프링은 항상 무상태로 설계
-
@Configuration과 싱글톤
-
@Configuration과 바이트코드 조작의 마법
-
※ 클라이언트 코드에서 “인터페이스 = new 구현 클래스”를 통해 하면 생기는 문제점? : 구체 클래스를 변경할 때 클라이언트 코드도 함께 변경 → DIP 위반(인터페이스에만 의존해야되는데 구현 클래스에도 의존하기 때문) & OCP 위반
- DIP란?
- DIP (Dependency inversion principle / 의존관계 역전 원칙) : 인터페이스에 의존, 구현 클래스 의존 X
※ 위 문제를 해결하기 위한 해결방안? : 인터페이스에만 의존할 수 있게 위부에서 생성자를 통해 구현 객체를 주입 ex) AppConfig