좋은 객체 지향 프로그래밍 SOLID
용어 | 개념 |
SRP | 단일 책임 원칙 = 하나의 클래스는 하나의 책임을 가짐 |
OCP | 개방 및 폐쇄 원칙 = 확장에는 열려 있으나, 변경에는 닫힘 |
LSP | 리스코프 치환 원칙 = 객체는 프로그램의 정확성을 지켜야 |
ISP | 인터페이스 분리 원칙 = 여러 개의 인터페이스가 범용 하나보다 우수함 |
DIP | 의존관계 역전 원칙 = 추상화에 의존, 구체화에 의존 x |
실무에서는 비즈니스 요구사항이 굉장히 자주 바뀌기 때문에 OCP와 DIP를 준수하는 것이 변경사항에 대비하기 유리하다고 한다.
* 아래 코드는OCP와 DIP를 위반한 예제 코드다.
public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}
실제 주문서비스를 기능하기 위한 OrderServiceImpl(구현체)는 OrderService(인터페이스)를 상속받아 생성된다.
이때, 할인 정책을 도입하기 위해 DIscountPolicy(인터페이스)에 의존관계를 가지며 private final을 통해 외부에서 고정된 값으로 실제 할인정책(구현체)를 사용한다.
-> //주석 처리를 통해 Fix에서 Rate 정책으로 변경하려는 코드임을 알 수 있다.
OCP와 DIP 위반
2편에서 객체에 대해 설명하며 사용했던 그림이다.
OrderServiceImpl을 운전자라고 치자.
DiscountPolicy가 자동차 역할, FixDiscountPolicy와 RateDiscountPolicy는 K3, 아반떼, 모델3라고 할 수 있다.
운전자는 어딘가로 이동하겠다는 목적을 위해 자동차를 이용하고자 한다. 이때 자동차를 타고 이동하는 것이 중요한 것이지 어떤 기종을 타는지는 목적을 이루는데 중요하지 않다.
그러나, 위 예제 코드에서는 K3를 타도록 지정되어 있는 것과 같다. - DIP 위반!
그리고 외부 사정으로 인해 K3를 이용하기 어려워 아반떼로 변경되는 상황에서 운전자에게 변경 정보를 입력해 아반떼를 찾아 타게 만들어야 하는 것이다. - OCP위반 !
Config 구성 클래스
운전자가 자동차 운전(실행)에만 집중할 수 있도록 자동차 설정은 Config라는 구성클래스를 통해 따로 관리해야한다.
package hello.core.order;
import ...
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;
}
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
package hello.core;
import ...
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(
new MemoryMemberRepository(),
new FixDiscountPolicy());
}
}
- 위 코드는 OrderService메서드에서 OrderServiceImpl 구현체를 생성하고 생성자 주입을 통해 FixDiscountPolicy 구현체를 주입하고 있다.
- 아래 코드는 수정된 OrderServiceImpl 클래스다. DiscountPolicy만 의존관계를 갖고 나머지는 생성자 주입을 통해 구현체를 관리한다.
OrderServiceImpl과 Appconfig 클래스는 각각 역할을 구분하여 책임을 부여하고 있다. 이를 통해 각 클래스가 어떤 역할을 하는지 명확하게 확인할 수 있고 변경사항에도 대비할 수 있다.
Config클래스의 추가적인 기능 설명
Spring에서 Configuration 클래스는 애플리케이션의 구성 정보를 포함하고, 빈(Bean) 설정과 관련된 것들을 정의하는 역할을 합니다. 이 클래스는 Java 기반으로 작성되며, @Configuration 어노테이션을 사용하여 선언됩니다.
주요 목적은 다음과 같습니다:
- 빈(Bean) 설정: @Bean 어노테이션을 사용하여 빈 객체를 정의합니다. 빈은 스프링 컨테이너에서 관리되는 객체로, 필요한 곳에서 주입(Dependency Injection) 받을 수 있습니다.
- 환경 설정 및 프로퍼티 설정: 데이터베이스 연결 정보, 외부 서비스 URL 등과 같은 환경 설정 정보를 정의할 수 있습니다.
- 조건부 빈 설정: 특정 조건에 따라 빈을 설정하거나 제외할 수 있습니다.
- 다른 Configuration 클래스와의 조합: 여러 개의 Configuration 클래스를 작성하고, 조합하여 하나의 애플리케이션 컨텍스트를 구성할 수 있습니다.
- AOP(Aspect-Oriented Programming) 설정: AspectJ와 같은 AOP를 사용하기 위한 설정을 추가할 수 있습니다.
- 컴포넌트 스캔 제어: @ComponentScan 어노테이션을 통해 어느 패키지에서 컴포넌트를 스캔할지 설정할 수 있습니다.
'Java Spring > Spring Framework' 카테고리의 다른 글
롬복, 컴포넌트 스캔 ~ 의존 관계 주입 Jav Spring 프레임워크의 기본 (6) (0) | 2023.12.04 |
---|---|
스프링 컨테이너와 싱글톤 컨테이너 Jav Spring 프레임워크의 기본 (5) (1) | 2023.11.29 |
회원 도메인 설계! Jav Spring 프레임워크의 기본 (3) (1) | 2023.11.27 |
JAVA는 객체 지향 프로그래밍? Jav Spring 프레임워크의 기본 (2) (0) | 2023.11.27 |
처음 자바 스프링을 공부한다면?Java Spring 프레임워크의 기본 (2) | 2023.11.26 |