※ 본 게시글은 인프런 스프링 핵심 원리 - 기본편 강의를 바탕으로 작성하였습니다.
강의 내용을 참고하여 개인적으로 정리한 글입니다.
장점 | 설명 |
---|---|
1. 클라이언트는 역할만 알면 된다 | 사용자는 인터페이스만 알고, 내부 구현을 몰라도 된다 |
2. 구현의 내부 구조를 몰라도 된다 | 내부 로직이 복잡해져도 클라이언트는 신경 쓸 필요가 없다 |
3. 구현이 바뀌어도 클라이언트 영향이 없다 | 구현 클래스의 이름, 내용이 바뀌어도 인터페이스만 유지 하면 된다 |
4. 구현 자체를 교체할 수 있다 | 예: Memory JDBC로 교체 가능, 테스트 환경 / 운영 환경 분리 가능 |
public interface PaymentService {
void pay(int amount);
}
public class KakaoPay implements PaymentService {
public void pay(int amount) {
System.out.println("카카오페이로 결제: " + amount);
}
}
public class TossPay implements PaymentService {
public void pay(int amount) {
System.out.println("토스로 결제: " + amount);
}
}
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void order(int amount) {
paymentService.pay(amount);
}
}
OrderService
는PaymentService
인터페이스만 알고 있고,
KakaoPay
,TossPay
가 어떤 방식으로 결제하는지 몰라도 된다
필요하면 그냥 구현 객체만 교체하면 끝! 💡
public class MemberService {
private MemberRepository repository = new MemberRepository();
public void joinMember(String name) {
repository.save(name);
}
}
public class MemberRepository {
public void save(String name) {
System.out.println("DB에 저장: " + name);
}
}
MemberService
- 회원 가입 조직만 담당MemberRepository
- 저장 로직만 담당
→ 변경이 일어날 때 한 클래스만 수정
1. OCP 위반 예제
public class DiscountService {
public int discount(String grade, int price) {
if (grade.equals("VIP")) {
return price - 1000;
} else {
return price - 500;
}
}
}
- 만약 GOLD 등급이 추가 된다면? - if문을 수정해줘야함(OCP 위반)
2. OCP 적용 에제
public interface DiscountPolicy {
int discount(int price);
}
public class BronzeDiscountPolicy implements DiscountPolicy {
public int discount(int price) {
return price - 500;
}
}
public class VipDiscountPolicy implements DiscountPolicy {
public int discount(int price) {
return price - 1000;
}
}
public class DiscountService {
private DiscountPolicy policy;
public DiscountService(DiscountPolicy policy) {
this.policy = policy;
}
public int calculate(int price) {
return policy.discount(price);
}
}
- 똑같이 GOLD 등급이 생긴다면? -
GoldDiscountPolicy
클래스를 추가만 하면 끝!
DiscountService
클래스는 변경 없이 재사용 가능
public class Car {
public void goForward() {
System.out.println("앞으로 천천히 간다");
}
}
public class SportsCar extends Car {
@Override
public void goForward() {
System.out.println("앞으로 빠르게 간다");
}
}
- 하위 클래스는 상위 클래스의 역할과 의미 꺠뜨리지 않고 대체 가능
- 동작 방식은 다를 수 있어도, 기능의 목적은 동일
1. ISP 위반 예제
interface Machine {
void print();
void scan();
void fax();
}
class OldPrinter implements Machine {
public void print() {
System.out.println("인쇄!");
}
public void scan() {
throw new UnsupportedOperationException("스캔 불가");
}
public void fax() {
throw new UnsupportedOperationException("팩스 불가");
}
}
Machine printer = new OldPrinter();
printer.print();
printer.scan(); // 사용하지도 않는 기능 구현해야 함 → ISP 위반
모든 기능을 하나의 인터페이스에 담아 놓아서 일부 기능만 필요한 클래스도 불필요하게 구현을 강요
2. ISP 적용 예제
interface Printer {
void print();
}
interface Scanner {
void scan();
}
class BasicPrinter implements Printer {
public void print() {
System.out.println("인쇄!");
}
}
Printer printer = new BasicPrinter();
printer.print();
필요한 기능만 인터페이스로 분리
클라이언트는 자신에게 꼭 필요한 기능만 구현
Service service = new Service();
일반적인 방식(제어 직접)
public class Controller {
private Service service;
public Controller(Service service) {
this.service = service;
}
}
제어를 외부(스프링 컨테이너)에서 맡김
DI
스프링에서는 생성자, 필드, Setter 주입 3가지 방식으로 사용
IoC와 DI는 글보단 코드로 보는것이 이해하기 더 쉬워서 코드를 짜보면서 다음 포스트로 넘어오겠습니다~