☁️ Strategy
스프링에서는 빈의 인스턴스 생성 전략에 대해 전략 패턴을 사용하여 구현했다.
전략 패턴은 디자인 패턴의 꽃이라고도 한다. 전략 패턴에느 3가지 요소가 사용되며 아래와 같다.
- 전략을 가지는
전략 객체
- 전략을 객체를 사용하는
컨텍스트
- 전략 객체를 생성하고, 컨텍스트에 주입하는
클라이언트
클라이언트가 전략 객체를 생성하고 컨텍스트에 주입함으로써, 컨텍스트는 외부에서 주입받은 전략에 따라 상이한 행동을 하는 것이 전략 패턴이다.
학교에서 선생님이 각 학생에게 필요한 과목을 학습하라고 명령하는 상황을 예시로 들어보자
과목
: 전략을 가지는 전략 객체 (수학, 과학, 국어)학생
: 전략 객체를 사용하는 컨텍스트 (수학 학습, 과학 학습, 국어 학습)선생님
: 전략(과목) 객체를 생성하고 컨텍스트(학생)에 주입하는 클라이언트
코드를 통해 구현해보면 아래와 같다. 먼저 전략 객체인 과목 클래스이다.
interface Subject {
void doStudy();
}
class Korean implements Subject {
@Override
public void doStudy() {
System.out.println("가, 나, 다, 라 ...");
}
}
class Math implements Subject {
@Override
public void doStudy() {
System.out.println("1 + 2 = 3 ...");
}
}
코드에서 doStudy 메서드는 전략을 수행하는 메서드가 된다. 다음은 컨텍스트에 해당하는 학생 클래스이다.
class Student {
void study(Subject subject) {
System.out.println("공부 시작");
subject.doStudy();
System.out.println("공부 끝");
}
}
메서드 레벨에서 Subject와 의존을 맺고 자신의 패턴에서 전략을 사용한다. 다음은 이를 주입하는 선생님 클래스이다.
public class Teacher {
public static void main(String[] args) {
Student 정현수 = new Student(); // 정현수 학생 생성
Subject 국어 = new Korean(); // 국어 과목 생성
// 정현수(컨텍스트)에게 국어(전략)공부 시키기
정현수.study(국어);
System.out.println();
Student 홍길동 = new Student();
Subject 수학 = new Math();
홍길동.study(수학);
}
}
공부 시작
가, 나, 다, 라 ...
공부 끝
공부 시작
1 + 2 = 3 ...
공부 끝
이러한 방식은 템플릿 메서드 패턴과 유사하다. 하지만 단일 상속이라는 상속의 제한이 있는 자바에서는 템플릿 메서드 패턴 보다는 전략 패턴이 더 많이 활용된다고 한다.
전략(Strategy) 패턴은 클라이언트가 전략을 생성하여 전략을 수행할 컨텍스트에게 주입하는 패턴이다.
스프링에서는?
스프링에 내부에서 전략 패턴을 어떻게 구현하여 사용했을까?
스프링에서는 빈의 인스턴스 생성 전략에 대해 전략 패턴을 사용하여 구현했다.
먼저 전략에 해당하는 InstantiationStrategy
인터페이스이다. 해당 인터페이스를 구현한 SimpleInstantiationStrategy
클래스가 전략이 된다.
public interface InstantiationStrategy {
Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3) throws BeansException;
Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3, Constructor<?> var4, Object... var5) throws BeansException;
Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3, @Nullable Object var4, Method var5, Object... var6) throws BeansException;
}
public class SimpleInstantiationStrategy implements InstantiationStrategy {
private static final ThreadLocal<Method> currentlyInvokedFactoryMethod = new ThreadLocal();
public SimpleInstantiationStrategy() {
}
@Nullable
public static Method getCurrentlyInvokedFactoryMethod() {
return (Method)currentlyInvokedFactoryMethod.get();
}
@Ovverride
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// ...
}
// ...
자세한 건 나중에 스프링 코드를 참조해서 정리해야겠다.
☁️ Template Callback
스프링 DI에 적용된 패턴이다.
전략 패턴과 모두 동일하지만 전략 패턴의 전략을 익명 내부 클래스로 사용한다는 차이점이 있다.
전략 패턴에서 예시로 들었던 과목-학생-선생님 코드를 예시로 들어보자.
interface Subject {
void doStudy();
}
class Student {
void study(Subject subject) {
System.out.println("공부 시작");
subject.doStudy();
System.out.println("공부 끝");
}
}
public class Teacher {
public static void main(String[] args) {
Student 정현수 = new Student();
정현수.study(new Subject() {
@Override
public void doStudy() {
System.out.println("가, 나, 다, 라 ... ");
}
});
System.out.println();
Student 홍길동 = new Student();
홍길동.study(new Subject() {
@Override
public void doStudy() {
System.out.println("1 + 2 = 3 ... ");
}
});
}
}
전략 인터페이스를 구현하는 전략 구체 클래스를 선언하고 생성하는 방법 대신 익명 내부 클래스로 전략을 구현하여 컨텍스트에게 전달하는 방식을 사용하였다.
위 코드는 중복 코드가 있기에 아래처럼 전략을 생성하는 코드를 컨텍스트 내부로 캡슐화할 수 있다.
class Student {
void study(String learn) {
System.out.println("공부 시작");
this.excuteSubject(learn).doStudy();
System.out.println("공부 끝");
}
private Subject excuteSubject(String learn) {
return new Subject() {
@Override
public void doStudy() {
System.out.println(learn);
}
};
}
}
public class Teacher {
public static void main(String[] args) {
Student 정현수 = new Student();
정현수.study("가, 나, 다, 라 ...");
System.out.println();
Student 홍길동 = new Student();
홍길동.study("1 + 2 = 3 ... ");
}
}
DI애서는 이런 방식의 템플릿 콜백 패턴을 사용한다.
'JAVA' 카테고리의 다른 글
디자인 패턴 - Template Method, Factory Mehtod (0) | 2024.01.20 |
---|---|
디자인 패턴 - Proxy, Decolator (0) | 2024.01.19 |
디자인 패턴 - Adapter (0) | 2024.01.19 |
SOLID (0) | 2024.01.18 |
BigDecimal 생성, 비교시 유의사항 (0) | 2024.01.17 |