왜 다른 프레임워크 대신 스프링을 사용하는가?
스프링은 자바 프레임워크이다. 그러므로 자바를 빼먹을수가 없는데 이 자바덕분에 다형성이 가능하기때문에 스프링을 선택했다. 또한 이러한 다형성을 잘 사용하려면, 즉 스프링을 잘 활용하려면 SOLID원칙을 잘 지켜야한다
결론적으로 스프링의 가장 중요한 점은 다형성과 SOLID이다
1. 다형성
스프링은 자바 언어 기반의 프레임워크이다
자바의 가장 큰 특징은 객체 지향 언어이다
유연하고 변경이 용이
- 객체지향에서 가장 중요한 점은 다형성이다
- 이러한 다형성덕분에 프로그램을 유연하고 변경이 용이하게 될수 있다
- 역할과 구현으로 나뉘는데 역할은 Interface(
MemberRepository
)이고 구현은 Interface(MemoryMemberRepository
)의 구현체이다 - 역할과 구현의 예시
- 운전자 - 포르쉐, 아반떼..등등
- 로미오 - 장동건, 류승범..등등
- USB - 마우스, 키보드,, 등등
- 하지만 다형성만으로는 DIP, OCP를 지킬수가없어 DI컨테이너가 탄생한다
클라이언트에게 영향을 주지 않는다
- 클라이언트(
MemberService
)는 대상의 역할(인터페이스)만 알면 된다 - 클라이언트(
MemberService
)는 구현 대상의 내부 구조를 몰라도 된다 - 클라어인트(
MemberService
)는 구현 대상의 내부 구조가 변경되어도 영향 X - 클라이언트(
MemberService
)는 구현 대상 자체를 변경해도 영향 X (MemoryMemberRepository
→JDBCtemplateMemberRepository
)
오버라이딩
- 오버라이딩이 있기 때문에 다형성이 가능하다
- 이러한 객체 지향의 다형성 덕분에 클라이언트를 변경하지 않고, 서버의 구현기능을 유연하게 변경 가능
스프링에선?
- 스프링에선 다형성을 활용한 제어의 역전(IoC), 의존관계 주입(DI)를 사용하여 구현을 편리하게 다룰수 있도록 지원한다.
- 즉 레고 블럭 조립하듯이 구현을 편리하게 변경할 수 있다.
2. 좋은 객체 지향 설계의 5가지 원칙 : SOLID
기존
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository = MemoryMemberRepository;
private final DiscountPolicy discountPolicy = new RateDiscountPolicy;
...
}
AppConfig 적용
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
...
}
public class AppConfig {
...
public OrderService orderService() {
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
구성 클래스(AppConfig)
IoC
- 프로그램에 대한 제어 흐름 및 인스턴스 생성에 대한 권한 즉, 설정 정보를 갖는 클래스
- 이렇게 클라이언트 구현 객체가 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것이 Ioc(제어의 역전)
DI
- AppConfig는 DI 컨테이너이다
- DI(Dependency Injection)은 특정한 기능을 구현하는 객체가 다른 클래스와의 의존 관계를 인터페이스에만 의존하고, 실제 어떤 클래스 구현 객체가 사용될지 모른다는 것을 의미한다
- 즉 클라이언트 코드를 변경하지않고, DI 컨테이너를 통해 클라이언트가 호출하는 대상의 타입 인스턴스를 변경할 수 있다
즉, 객체를 생성하고 관리하면서 의존관계를 연결해 주는 것을 DI 컨테이너라고한다
SRP
한 클래스는 하나의 책임만 가져야한다
- 구현 객체를 생성하고 연결하는 책임, 즉 구성 단계는 AppConfig 클래스
- 클라이언트 객체는 실행하는 책임만 담당
DIP
추상화에 의존해야지, 구체화에 의존하면 안된다
- 클라이언트 코드는 인터페이스에만 의존해야한다
- 하지만 클라이언트 코드는 인터페이스만으로는 아무것도 실행할 수 없다
- Appconfig(어플리케이션 구성파일)을 구성하여 객체인스턴스를 직접 생성하고, 클라이언트 코드에 의존관계를 주입한다
OCP
소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다
- AppConfig에서
FixDiscountPolicy
→RateDiscountPolicy
로 변경할때 클라이언트 코드를 건들지 않고(=변경에는 닫혀있음) 따로 구성 영역을 담당하는 설정 클래스를 만들어 소프트웨어 요소를 새롭게 확장할 수가 있다. - 소프트웨어 요소를 새롭게 확장하여도 사용 영역(클라이언트)는 변하지 않는다
댓글 쓰기