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;
}
...
}