Separation of Concerns, SoC
소프트웨어 상에서 구조를 패턴, 역할, 기능 등 각각 맞게 분야 별로 분리해서 작성하는 것을 말한다. 분리해서 작성할 때, 특성에 맞게 하나의역할
을 부여해서 작성해야 한다.
- Spring에서 SoC를 통해서 결합도는 낮게, 응집도는 높이면서 프로그램에서 실세계를 반영하려 한다.
- 클래스 간의 의존성을 낮추면 유지 보수와 객체의 재사용이 쉬워진다.
- 모듈 내부 요소들 간의 기능적 관련성이 높으면 독립성이 높아지므로 재사용에 용이하다.
애플리케이션의 전체 동작 방식을 구성하기 위해 구현 객체를 생성
하고 연결
하는 책임을 가진 별도의 설정 클래스를 만들어 기존 코드의 문제점을 해결할 수 있다.
public class OrderServiceImpl implements OrderService{
private final MemberRepo mr = new MemoryMemberRepository();
private final DiscountPolicy dp = new FixDiscountPolicy();
...
}
이 코드에서 할인 정책을 변경할 경우 소스 코드도 변경되어야 하므로 OCP를 위배한다. 또한, 인터페이스와 그 구현체에도 의존하고 있으므로 DIP에도 위반을 하고 있다. 따라서 인터페이스에만 의존할 수 있도록 의존관계를 변경해야 한다. 저 클래스에서 특정 구현체를 설정하는 것이 아닌, 관리자같은 클래스(AppConfig)로 관리하도록 변경하면 된다.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
// 중복된 부분이 있으므로 함수를 생성해서 사용
public MemberRepository memberRepository() {
return new MemoryMemberRepository(); // 구현 클래스
}
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy(); // 구현 클래스
}
}
}
생성자 주입
으로 연결해준다.따라서 사용 영역의 코드는 변경할 필요가 없으며, 구성 영역의 코드만 변경하면 된다.
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
...
}
외부
에 맡기고 실행
에만 집중할 수 있게 되었다.관심사의 분리
객체를 생성하고 연결하는 역할과 실행하는 역할이 명확히 분리 되었다.
DI
클라이언트인 memberServiceImpl의 입장에서 보면 의존관계를 마치 외부에서 주입해주는 것 같다고 해서DI(Dependency Injection, 의존관계 주입)
이라고 한다.
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;
}
...
}