[Spring] λμμΈ ν¨ν΄ - Strategy Pattern
by rlaehddnd0422μ΄ μ ν¬μ€ν
μμ μμλ³Έ Template Method Patternμ "μΆμ ν΄λμ€"μ μμ ν΄λμ€μμ λ³κ²½λλ λ‘μ§μ 골격μ μ μΈ λ° κ³΅ν΅μΌλ‘ μ¬μ©νλ λ‘μ§μ 골격μ μ μ(*ꡬν)νκ³ "μμ ν΄λμ€"μμλ λΆλͺ¨ ν΄λμ€λ₯Ό μμλ°μ λ³κ²½λλ λ‘μ§μ μ μ(*ꡬν)νλ λ°©μμ΄μμ΅λλ€.
μ΄ ν¨ν΄μμλ μμμ μ¬μ©νμ¬ "νΉμ " λΆλͺ¨ ν΄λμ€μ μμ‘΄νμ§λ§, μλ μ½λμ κ°μ΄ μμ ν΄λμ€ μ
μ₯μμ 'ꡬν ν΄λμ€'λ§ λ± μκ°ν΄λ³΄λ©΄ λΆλͺ¨ ν΄λμ€μ κΈ°λ₯μ μ ν μ¬μ©νμ§λ μλλ°, λΆλͺ¨ ν΄λμ€μ μν₯μ λ°κ² λ©λλ€.
@Slf4j
public class SubClassLogic1 extends AbstractTemplate {
@Override
protected void call() {
log.info("λΉμ¦λμ€ λ‘μ§1 μ€ν");
}
}
+ λ³λμ μμ ν΄λμ€λ μ΅λͺ
ν΄λμ€λ₯Ό λ§λ€μ΄μΌ νλ λΆλΆλ κ½€ λ²κ±°λ‘λ€λ λ¨μ μ΄ μμ΅λλ€.
μ΄λ²μλ Template-Method ν¨ν΄μ λ¨μ μ 보μν μ μλ Strategy ν¨ν΄μ λν΄ μμ보λλ‘ νκ² μ΅λλ€.!
Strategy ν¨ν΄μ΄λ?
μ¬ννκ² μ€λͺ νμλ©΄ μ΄λ μ΅λλ€.
- λ³νμ§ μλ λΆλΆμ Contextμ ν΄λμ€λ‘ μ μ λ° κ΅¬ν
- Contextκ° Template Method Patternμ ν νλ¦Ώ μν μ νλ€κ³ 보μλ©΄ λ©λλ€.
- λ³νλ λΆλΆμ Strategyμ μΈν°νμ΄μ€λ‘ μ μ λ° μ μΈ
- Strategy μΈν°νμ΄μ€μ ꡬνμ²΄λ‘ λ³νλ λΆλΆμ ꡬνν©λλ€.
- Strategyλ Template Method Patternμ λ³νλ μκ³ λ¦¬μ¦ μν
- Springμ λ€λ£¨λ©΄μ κΈ°λ³Έμ μΌλ‘ μ¬μ©ν΄μ¨ λ°©μμ΄ λ°λ‘ μ λ΅ ν¨ν΄μ΄λΌκ³ λ³Ό μ μμ.
μ λ΅ ν¨ν΄(Strategy Pattern)μ μλ?
μκ³ λ¦¬μ¦ μ νκ΅°μ μ μνκ³ κ°κ°μ μΊ‘μννμ¬ μνΈ κ΅ν κ°λ₯νκ² λ§λ€μ΄ μκ³ λ¦¬μ¦μ λ 립μ μΌλ‘ λ³κ²½ κ°λ₯νκ² λ§λ€μ.
Strategy ν¨ν΄ v1 - Context μμ± μμ μ μμ‘΄κ΄κ³ μ£Όμ
Strategy
public interface Strategy {
void call();
}
- call() : λ³νλ λΆλΆμΈ 골격μ μΈν°νμ΄μ€λ‘ μ μΈν΄μ£Όμμ΅λλ€.
- ꡬν체μ λ°λΌ μ λμ μΌλ‘ ꡬν
@Slf4j
public class StrategyLogic1 implements Strategy {
@Override
public void call() {
log.info("λΉμ¦λμ€ λ‘μ§1 μ€ν");
}
}
@Slf4j
public class StrategyLogic2 implements Strategy {
@Override
public void call() {
log.info("λΉμ¦λμ€ λ‘μ§2 μ€ν");
}
}
Context
Contextμμλ Strategyλ₯Ό μ»΄νμΌ μμ μμ κ°μλΌμΈ μ μλλ‘ μ£Όμ λ°μ μ¬μ©ν©λλ€.
- λ³νμ§ μλ λΆλΆμΈ κ³΅ν΅ λ‘μ§μ execute()μ ꡬννκ³ λ³νλ λΆλΆμ μ£Όμ λ°μ Strategyμ ν΅ν΄ μμνμ¬ μ€νν©λλ€.
- Strategy Patternμ ν΅μ¬ : Contextλ Strategy μΈν°νμ΄μ€μλ§ μμ‘΄νλ€λ μ
- μ¦, Strategyμ ꡬν체λ₯Ό λ³κ²½νκ±°λ μλ‘ λ§λ€μ΄λ Context μ½λμλ μν₯μ μ£Όμ§ μμ΅λλ€.
@Slf4j
public class ContextV1 {
private Strategy strategy;
public ContextV1(Strategy strategy) {
this.strategy = strategy;
}
public void execute() {
long startTime = System.currentTimeMillis();
// λΉμ¦λμ€ λ‘μ§ μ€ν
strategy.call(); // μμ
// λΉμ¦λμ€ λ‘μ§ μ’
λ£
long endTime = System.currentTimeMillis();
log.info("result Time = {}", endTime - startTime);
}
}
- 1. context - Strategy ꡬν체λ₯Ό μ£Όμ λ°μ μμ±
- 2. execute() μ€ν
- 2-1. κ³΅ν΅ λ‘μ§ μ€ν
- 2-2. λΉμ¦λμ€ λ‘μ§ : μ£Όμ ν Strategy ꡬν체μ μμνμ¬ μ€ν
- 3. contextλ λλ¨Έμ§ λ‘μ§μ μ€ν.
@Test
public void strategyTest() throws Exception {
Strategy strategyLogic1 = new StrategyLogic1();
ContextV1 context1 = new ContextV1(strategyLogic1);
context1.execute();
}
+ Tip : λ§μ°¬κ°μ§λ‘ μ΅λͺ ν΄λμ€λ₯Ό ν΅ν΄ Strategy ꡬν체 μμ±ν΄λ ok
+ Tip μΈν°νμ΄μ€μ default, staticμ μ μΈνκ³ λ©μλκ° 1κ° μ μΈλμ΄ μμ λ λλ€μ μ¬μ© κ°λ₯
- λκ° μ΅μν λ°©λ²μ΄λΌκ³ μκ°μ΄ λ€μλλ°, Spring μ ν리μΌμ΄μ μ κ°λ°ν λ μ ν리μΌμ΄μ λ‘λ© μμ μ μμ‘΄κ΄κ³ μ£Όμ μ ν΅ν΄ νμν μμ‘΄κ΄κ³λ₯Ό λͺ¨λ λ§Ίμ΄λκ³ λ λ€μμ μ€μ μμ²μ μ²λ¦¬νλ κ²κ³Ό κ°μ μ리μμ΅λλ€.
- Contextμ Strategyλ₯Ό μ£Όμ λ°μ μ¬μ©νκ² λλ©΄ 쑰립(μ£Όμ ) μ΄ν λ³κ²½μ΄ λ²κ±°λ‘κ³ μ±κΈν€ ν¨ν΄μΌ λ λμμ±κΉμ§ κ³ λ €ν΄μ£Όμ΄μΌ νλ λ¬Έμ κ° μμ΅λλ€. ( μ΄ κ²½μ° Contextλ₯Ό μλ‘ μμ±ν΄μ λ€λ₯Έ ꡬν체λ₯Ό μ£Όμ λ°μ μ¬μ©νλ λ°©λ²μ΄ κΆμ₯λ¨ )
- μ΄μ΄ μ 쑰립 - ν μ¬μ© λ°©μ λ§κ³ λ μ μ°νκ² μ λ΅ ν¨ν΄μ μ¬μ©νλ λ°©λ²μ μμ보λλ‘ νκ² μ΅λλ€.
Strategy ν¨ν΄ v2 - Context μμ± μμ μ΄ μλ λ©μλμ Strategyλ₯Ό νλΌλ―Έν° λ°μΈλ©
λ°λ‘ μλμ κ°μ΄ Contextμ Strategyλ₯Ό μ£Όμ νμ§ μκ³ λ©μλμ νλΌλ―Έν°λ‘ Strategyλ₯Ό μ λ¬λ°μ μ¬μ©νλ λ°©μμ λλ€.
@Slf4j
public class ContextV2 {
public void execute(Strategy strategy) {
long startTime = System.currentTimeMillis();
// λΉμ¦λμ€ λ‘μ§ μ€ν
strategy.call(); // μμ
// λΉμ¦λμ€ λ‘μ§ μ’
λ£
long endTime = System.currentTimeMillis();
log.info("result Time = {}", endTime - startTime);
}
}
μ΄λ¬λ©΄ μ€νμμ μ μ λ΅μ΄ λ³κ²½λ λ, Contextλ₯Ό κ΅³μ΄ λ§λ€μ΄μ€ νμκ° μμ΄μ§κ² λ©λλ€! μ΄λ κ² λ§μ΄μ£
@Test
public void strategyTest() throws Exception {
Strategy strategyLogic1 = new StrategyLogic1();
Strategy strategyLogic2 = new StrategyLogic2();
ContextV2 context = new ContextV2();
context.execute(strategyLogic1);
context.execute(strategyLogic2);
}
μ’ λ ν΄λ¦°νκ² μ§λ©΄ μ΄λ κ² ν μ μμ£ .
@Test
public void strategyV4() throws Exception {
ContextV2 context = new ContextV2();
context.execute(() -> {
log.info("λΉμ¦λμ€ λ‘μ§1 μ€ν");
});
context.execute(() -> {
log.info("λΉμ¦λμ€ λ‘μ§2 μ€ν");
});
}
νμ§λ§ μ§κΈ μ°λ¦¬κ° μνλ κ²μ μ ν리μΌμ΄μ μμ‘΄ κ΄κ³λ₯Ό μ€μ νλ κ² μ²λΌ μ 쑰립 - ν μ€νμ΄ μλλΌ, λ¨μν μ½λλ₯Ό μ€νν λ λ³νμ§ μλ ν νλ¦Ώμ΄ μκ³ , κ·Έ ν νλ¦Ώ μμμ μνλ λΆλΆλ§ μ΄μ§ λ€λ₯Έ μ½λλ₯Ό μ€ννκ³ μΆμ κ²μ΄λ κ·Έλ° μ μμλ v2κ° λ μ ν©ν κ² κ°μ΅λλ€.
Template-Callback ν¨ν΄
GOFμ Strategy ν¨ν΄μ Springμμλ Template Callback ν¨ν΄μΌλ‘ μΉν©λλ€.
- Springμμ JdbcTemplateμ²λΌ λ€μν ν νλ¦Ώ μ½λ°± ν¨ν΄μ΄ μ¬μ©λλλ° xxxTemplateμ΄λΌ μ°μΈ μ½λλ ν νλ¦Ώ μ½λ°± ν¨ν΄μ΄ μ μ©λμλ€κ³ λ΄λ λ©λλ€.
- Strategy ν¨ν΄μ Context -> Template, Strategy -> Callback ( λͺ μΉλ§ λ€λ¦ )
callback ν¨μλΌ ν¨μ, λ€λ₯Έ μ½λμ μΈμλ‘ λ겨주λ μ€ν κ°λ₯ν μ½λλ₯Ό λ§ν©λλ€. (* callbackμ μ‘°κΈ λ μ½κ² λ§νλ©΄ μ½λκ° νΈμΆ(call)μ λλλ° μ€μ μ€νμ μ½λλ₯Ό λκ²¨μ€ κ³³μ λ€(back)μμ μ€νλλ€λ λ»)
@Slf4j
public class TemplateCallbackTest {
@Test
public void callbackTest() throws Exception {
TimeLogTemplate template = new TimeLogTemplate();
Callback callback = new Callback() {
@Override
public void call() {
log.info("λΉμ¦λμ€ λ‘μ§ μ€ν1");
}
};
template.execute(callback);
}
}
// λ©μλκ° νλλ©΄ λλ€μ μ μ© ok.
@Test
void callbackV2() {
TimeLogTemplate template = new TimeLogTemplate();
template.execute(() -> log.info("λΉμ¦λμ€ λ‘μ§1 μ€ν"));
template.execute(() -> log.info("λΉμ¦λμ€ λ‘μ§2 μ€ν"));
}
Template-Callback ν¨ν΄ μ μ©
* λλ€μμΌλ‘ μ½λλ₯Ό κΉλνκ² μμ±νμμ΅λλ€.
Controller
@GetMapping("/v5/request")
public String request(@RequestParam String itemId) {
return template.execute("OrderService.orderItem()", () -> {
orderService.orderItem(itemId);
return "ok";
});
}
- template.execute(msg, new TraceCallback(){..}) : ν νλ¦Ώμ μ€ννλ©΄μ μ½λ°±μ μ λ¬ν©λλ€.
Service
public void orderItem(String itemId) {
template.execute("OrderService.orderItem()", () -> {
orderRepository.save(itemId);
return null;
});
}
Repository
public void save(String itemId) {
template.execute("OrderRepository.save()", () -> {
if (itemId.equals("ex")) {
throw new IllegalStateException("μμΈ λ°μ");
}
sleep(1000);
return null;
}
);
}
<μ 리>
- ν νλ¦Ώ μ½λ°± ν¨ν΄κΉμ§ μ§νν΄λ³΄λ©΄μ λ³νλ μ½λμ λ³νμ§ μλ μ½λ(곡ν΅κΈ°λ₯)λ₯Ό λΆλ¦¬ν΄λ³΄λ©΄μ μ½λλ₯Ό μ΅μ ν ν΄λ³΄μμ΅λλ€.
- 곡ν΅μ μΌλ‘ κ³μΈ΅μ μλ³Έ μ½λλ₯Ό μμ ν΄μΌ νλ건 λ§μ°¬κ°μ§ μλλ°μ, μ§κΈκΉμ§ μ€λͺ ν λ°©μμ μ€μ μ€νλ§ μμμ λ§μ΄ μ¬μ©λλ λ°©μμ΄μ§λ§, μ€μΌμΌμ΄ 컀μ§μλ‘ κ³ μ³μΌ ν μλ³Έ μ½λλ λ§μμ§λ κ²μ λΆλ³ν©λλ€.
- λ€μμλ νλ‘μ ν¨ν΄μ μ μ©μμΌ μλ³Έ μ½λλ₯Ό μλμ§ μκ³ λ‘κ·Έ μΆμ κΈ°λ₯Ό μ μ©ν μ μλ λ°©λ²μ μμ보λλ‘ νκ² μ΅λλ€.
<μ°Έκ³ μλ£>
'π Backend' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
λΈλ‘κ·Έμ μ 보
Study Repository
rlaehddnd0422