1. μ μ
π‘ μ λ΅ ν¨ν΄ , μ€νΈλν°μ§ ν¨ν΄ (strategy pattern)
μκ³ λ¦¬μ¦κ΅°μ μ μνκ³ κ°κ° μΊ‘μννμ¬ κ΅νν΄μ μ¬μ©ν μ μλλ‘ λ§λ λ€. μ€νΈλν°μ§ ν¨ν΄μ νμ©νλ©΄ μκ³ λ¦¬μ¦μ μ¬μ©νλ ν΄λΌμ΄μΈνΈμλ λ 립μ μΌλ‘ μκ³ λ¦¬μ¦μ λ³κ²½ν μ μλ€.
'νμ(Behavioral) ν¨ν΄'
νμλ₯Ό ν΄λμ€λ‘ μΊ‘μνν΄ λμ μΌλ‘ (μ λ΅μ λ§κ²) νμλ₯Ό μμ λ‘κ² λ°κΏ μ μκ² ν΄μ£Όλ ν¨ν΄
μ λ΅(Strategy)μ μ½κ² λ°κΏ μ μλλ‘ ν΄μ£Όλ ν¨ν΄
μ¬κΈ°μ μ λ΅μ΄λ? μ΄λ€ λͺ©μ μ λ¬μ±νκΈ° μν΄ μΌμ μννλ λ°©μ. λΉμ¦λμ€ κ·μΉ, λ¬Έμ ν΄κ²° μκ³ λ¦¬μ¦ λ±
2. [μμ ] μ€λ¦¬κ²μ μ΄ν리μΌμ΄μ
// μ€λ¦¬ μνΌν΄λμ€
public abstract class Duck {
public Duck() {}
public void quack() {
System.out.println("κ½₯~~");
}
public void swim() {
System.out.println("μμνλ€~~");
}
public abstract void display(); // ꡬ체μ μΈ μ€λ¦¬μμ μ¬μ μ
}
// Duck μ νμ₯νμ¬ ReadHeadDuck μ μ
public class RedHeadDuck extends Duck {
@Override
public void display() {
System.out.println("RedHeadDuck.display() μΆλ ₯");
}
}
// Duck μ νμ₯νμ¬ MallardDuck μ μ
public class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("MallardDuck.display() μΆλ ₯");
}
}
(1) λ¬Έμ 1 : μμμ μν λ¬Έμ
μꡬμ¬ν : μ€λ¦¬κ° λ μ μκ² ν΄μ£ΌμΈμ. κ·Έλ¦¬κ³ Rubber Duck λ μΆκ°ν΄μ£ΌμΈμ. κ·Όλ° μ΄ κ³ λ¬΄μ€λ¦¬λ λ μ μμ΄μ.
// μ€λ¦¬ μνΌν΄λμ€
public abstract class Duck {
public Duck() {}
public void quack() {
System.out.println("κ½₯~~");
}
public void swim() {
System.out.println("μμνλ€~~");
}
// λ μ μκ² κΈ°λ₯ μΆκ°
public void fly() {
System.out.println("μ€λ¦¬λ λ€~~");
}
public abstract void display(); // ꡬ체μ μΈ μ€λ¦¬μμ μ¬μ μ
}
// Duck μ νμ₯νμ¬ RubberDuck μ μ (λ μ μλ μ€λ¦¬ μΆκ°)
public class RubberDuck extends Duck {
@Override
public void display() {
System.out.println("RubberDuck.display() μΆλ ₯");
}
@Override
public void fly() {
// μμλλ¬Έμ μν₯μ΄ μμ΄ λ μ μλλ‘ μ¬μ μ νλ€.
System.out.println("κ³ λ¬΄μ€λ¦¬λ λͺ» λ μμ");
}
}
- λ μ μλ κΈ°λ₯μ μΆκ°ν΄μ£ΌμΈμ. : Duck μΆμν΄λμ€μ λ μ μλ κΈ°λ₯ fly() λ₯Ό μΆκ°ν΄μ ν΄κ²°νλ€.
- Rubber Duck λ₯Ό μΆκ°ν΄μ£ΌμΈμ. : Duck ν΄λμ€λ₯Ό νμ₯ν΄μ RubberDuck λ₯Ό μ μνλ€.
- κ·Όλ°, Rubber Duckμ λ μ μμ΄μ. : Duck ν΄λμ€λ₯Ό μμλ°κ³ μμ΄ λ κ³ μλ€. fly() λ₯Ό μ¬μ μν΄μ λ μ μκ² νλ€.
λ¬Έμ λ μΌμΆ ν΄κ²°λ κ²μΌλ‘ 보μΈλ€.
κ·Έλ°λ°, μμΌλ‘ Rubber Duckκ³Όκ°μ΄ λ μ μλ μ€λ¦¬κ° λ μΆκ°λλ€λ©΄ κ·Έλλ§λ€ λ©μλλ₯Ό νλνλ νμΈνλ©° μ€λ²λΌμ΄λ ν΄μ ꡬνν΄μ€μΌνλ€.
(2) λ¬Έμ 2 : μΈν°νμ΄μ€μ μν λ¬Έμ
νμ¬μμ 1κ°μλ§λ€ μλ‘μ΄ μ€λ¦¬λ₯Ό μ λ°μ΄νΈ ν μμ μ΄λΌκ³ νλ€. λ κ°κ°μ νΉμ±λ λ€μν κ²μ΄λΌκ³ νλ€. κ½₯ νλ μ리λ λ€ λ€λ₯΄κ³ , λ μ μλ μ€λ¦¬λ μμ κ²μ΄λΌκ³ νλ€. νμ¬ μμ€ν μ μμμΌλ‘ μ€λ¦¬λ₯Ό μμ±νκ³ μκΈ°λλ¬Έμ μ€λ¦¬κ° μΆκ° λ λλ§λ€ quack() λ©μλμ fly() λ©μλλ₯Ό λ€ μ΄ν΄λ΄μΌ νλ€.
μ΄λ¬λ©΄ μμνμ©μ΄ νλΉνμ§ μλ€. κ·Έλ λ€λ©΄ μΈν°νμ΄μ€λ₯Ό μ¬μ©ν΄λ³΄λ©΄ μ΄λ¨κΉ?
// fly μΈν°νμ΄μ€
public interface Flyable {
void fly();
}
// quack μΈν°νμ΄μ€
public interface Quackable {
void quack();
}
// RubberDuck : Duck μ μμλ°κ³ , Flyable κ³Ό Quackable μΈν°νμ΄μ€λ₯Ό ꡬν
public class RubberDuck extends Duck implements Flyable, Quackable {
@Override
public void display() {
System.out.println("RubberDuck.display() μΆλ ₯");
}
// μΈν°νμ΄μ€ ꡬν
public void fly() {
System.out.println("κ³ λ¬΄μ€λ¦¬λ λͺ» λ μμ");
}
public void quack(){
System.out.println("κΎΈμ‘");
}
}
μΈν°νμ΄μ€λ₯Ό μ¬μ©νλ©΄ κ° μλΈν΄λμ€μμ λͺ¨λ μΈν°νμ΄μ€λ₯Ό ꡬνν΄μ£Όμ΄μΌ νλ μ½λ μ€λ³΅μ΄ μμ²λκ² λ°μνλ€. λ©μλ λͺκ° μ€λ²λΌμ΄λ ν΄μΌνλ κ²μ νΌνλ €λ€κ° λͺ¨λ Duck μ μλΈν΄λμ€λ₯Ό μ λΆ κ³ μ³μΌ νκ² λλ²λ¦°λ€.
3. λ€λ₯Έ ν΄κ²°λ°©λ²
μμμ νμΈν λ¬Έμ μ 2κ°μ§
- μμμ μ¬μ©νλ λ°©λ²μ μλΈν΄λμ€λ€μ νλμ΄ λ°λ μ μλλ°λ λͺ¨λ μλΈν΄λμ€λ€μ΄ νλμ νλμ μ¬μ©νλ κ²μ΄ λ¬Έμ κ° λλ€.
- Flyable, Quackable μΈν°νμ΄μ€λ₯Ό μ¬μ©νλ λ°©λ²μ μ½λμ¬μ¬μ©μ ν μ μλ€. μ¦, νκ°μ§μ νλμ λ°κΏλλ§λ€ κ·Έ νλμ΄ μ μλμ΄ μλ λͺ¨λ μλΈν΄λμ€λ€μ μ λΆ μ°Ύμμ μ½λλ₯Ό κ³ μ³μ€μΌνκ³ , κ·Έ κ³Όμ μμ μκΈ°μΉλͺ»ν μλ‘μ΄ λ²κ·Έκ° λ°μν κ°λ₯μ±μ΄ λ§€μ° λλ€.
π λμμΈμμΉ
μ΄ν리μΌμ΄μ μμ λ¬λΌμ§λ λΆλΆλ€ μ°Ύμλ΄κ³ , λ¬λΌμ§μ§ μλ λΆλΆμΌλ‘λΆν° λΆλ¦¬μν¨λ€.
λ¬λΌμ§λ λΆλΆμ μ°Ύμλ΄μ λλ¨Έμ§ μ½λμ μν₯μ μ£Όμ§ μλλ‘ μΊ‘μν μμΌμ€λ€.
λ¬λΌμ§λ λΆλΆ : fly(), quack() -> Duck ν΄λμ€λ‘λΆν° λΆλ¦¬μν€κΈ°μν΄ κ° νλμ λνλΌ ν΄λμ€μ μ§ν©μ λ§λ€μ΄μ£Όμ.
// fly νλ ν΄λμ€ μ§ν©
public interface FlyBehavior {
void fly();
}
// quack νλ ν΄λμ€ μ§ν©
public interface QuackBehavior {
void quack();
}
// λ μ μλ νλ ꡬν : FlyNoWay (νλμ μμ)
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("λͺ» λ μμ!");
}
}
// λ μ μλ νλ ꡬν : FlyWithWings (νλμ μμ)
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("λ κ³ μμ΄μ!");
}
}
// κ½₯ ꡬν : QuackBehavior (νλμ μμ)
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("κ½₯");
}
}
// κ°μ§ κ½₯ ꡬν : QuackBehavior (νλμ μμ)
public class FakeQuack implements QuackBehavior {
public void quack() {
System.out.println("κΎΈμ μ‘");
}
}
μ΄λ κ² νλμ λΆλ¦¬μν¨λ€. νλμ κ΄ν μΈν°νμ΄μ€κ° μκΈ°κ³ κ΅¬μ²΄μ μΈ νλμ ꡬννλ ν΄λμ€λ€μ΄ κ°κ° μμ±λλ€.
μ΄μ λμ΄μ λλ νλ fly() μ μ리λ΄λ νλ quack() λ₯Ό Duck ν΄λμ€λ κ·Έ μλΈν΄λμ€μμ ꡬννμ§ μκ³ λ€λ₯Έ ν΄λμ€μ μμμ ν΄μ£Όκ² λλ€.
π λμμΈμμΉ
μμ보λ€λ ꡬμ±μ νμ©νλ€.
π λμμΈμμΉ
ꡬνμ΄ μλ μΈν°νμ΄μ€μ λ§μΆ°μ νλ‘κ·Έλλ°νλ€.
// Duck ν΄λμ€μμ μ΄μ νλμ μ§μ μ²λ¦¬ νμ§μκ³ κ° νλμ μ°Έμ‘°νκ³ μμν΄μ€λ€.
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("μμνλ€~~");
}
public abstract void display();
}
"A λ B μ΄λ€" λ³΄λ€ "A μλ B κ° μλ€" κ° λμ μ μλ€.
κ°κ°μ μ€λ¦¬λ€μκ²λ FlyBehavior μ QuackBehavior μ΄ μμΌλ©° κ°κ° λλ νλκ³Ό μ리λ΄λ νλμ μμλ°λλ€.
μ΄λ°μμΌλ‘ λ ν΄λμ€λ₯Ό ν©μΉλ κ²μ κ΅¬μ± (composition) μ μ΄μ©νλ κ²μ΄λΌκ³ νλ€.
μ¬κΈ°μ μ€λ¦¬ ν΄λμ€λ νλμ μμλ°λ λμ μ¬λ°λ₯Έ νλ κ°μ²΄λ‘ ꡬμ±λ¨μΌλ‘μ¨ νλμ λΆμ¬λ°κ² λλ€.
4. μμ 2
1. Strategy μΈν°νμ΄μ€
public interface Strategy {
void algorithmInterface();
}
2. Strategy μΈν°νμ΄μ€λ₯Ό ꡬν ( κ° μ λ΅μ ꡬννλ€)
// μ λ΅ A ꡬν
@Slf4j
public class StrategyLogicA implements Strategy {
@Override
public void algorithmInterface() {
log.info("μ λ΅ μΈν°νμ΄μ€ ꡬν A");
}
}
// μ λ΅ B ꡬν
@Slf4j
public class StrategyLogicB implements Strategy {
@Override
public void algorithmInterface() {
log.info("μ λ΅ μΈν°νμ΄μ€ ꡬν B");
}
}
3. μ λ΅μ μ¬μ©νλ Context
@Slf4j
public class Context {
public void execute(Strategy strategy) {
Long startTime = System.currentTimeMillis();
// λΉμ¦λμ€ λ‘μ§ μ€ν
strategy.algorithmInterface(); // κ° μ λ΅μ μμ
// λΉμ¦λμ€ λ‘μ§ μ’
λ£
Long endTime = System.currentTimeMillis();
Long resultTime = endTime - startTime;
log.info("resultTime = {}", resultTime); // μ€νμκ° μΆλ ₯
}
}
4. μ€ν
/**
* μ λ΅ ν¨ν΄ μ μ©
*/
@Test
void strategy1() {
Context context = new Context();
context.execute(new StrategyLogicA()); // Contextμ λ‘μ§ μ€νμ νλΌλ―Έν°λ‘ μ λ΅ μ λ¬
context.execute(new StrategyLogicB());
}
/**
* μ λ΅ ν¨ν΄ μ΅λͺ
λ΄λΆ ν΄λμ€, λλ€ μ¬μ©νλ κ²½μ°
*/
@Test
void strategy2() {
Context context = new Context();
context.execute(new Strategy() { // μ΅λͺ
λ΄λΆ ν΄λμ€ κ°λ₯
@Override
public void algorithmInterface() {
log.info("μ λ΅ μΈν°νμ΄μ€ ꡬν - A");
}
});
context.execute(() -> log.info("μ λ΅ μΈν°νμ΄μ€ ꡬν2")); // λλ€ κ°λ₯
}
5. μΆλ ₯κ²°κ³Ό νμΈ
// strategy1 κ²°κ³Ό (λ‘κ·Έμ ν¨ν€μ§λͺ
μλ΅)
..μλ΅..StrategyLogicA - μ λ΅ μΈν°νμ΄μ€ ꡬν A
..μλ΅..Context - resultTime = 11
..μλ΅..StrategyLogicB - μ λ΅ μΈν°νμ΄μ€ ꡬν B
..μλ΅..Context - resultTime = 0
// strategy2 κ²°κ³Ό (λ‘κ·Έμ ν¨ν€μ§λͺ
μλ΅)
..μλ΅..ContextTest - μ λ΅ μΈν°νμ΄μ€ ꡬν - A
..μλ΅..Context - resultTime = 1
..μλ΅..ContextTest - μ λ΅ μΈν°νμ΄μ€ ꡬν2
..μλ΅..Context - resultTime = 1
5. UML Class Diagram
6. GOF λμμΈ ν¨ν΄ μ μ
μκ³ λ¦¬μ¦ μ νκ΅°μ μ μνκ³ κ°κ°μ μΊ‘μννμ¬ μνΈ κ΅ν κ°λ₯νκ² λ§λ€μ. μ λ΅μ μ¬μ©νλ©΄ μκ³ λ¦¬μ¦μ μ¬μ©νλ ν΄λΌμ΄μΈνΈμ λ 립μ μΌλ‘ μκ³ λ¦¬μ¦μ λ³κ²½ν μ μλ€.
μ λ΅ ν¨ν΄μ λ³νμ§ μλ λΆλΆμ Context (λ¬Έλ§₯) λΌλ κ³³μ λκ³ , λ³νλ λΆλΆμ Strategy λΌλ μΈν°νμ΄μ€λ₯Ό λ§λ€κ³ ν΄λΉ μΈν°νμ΄μ€λ₯Ό ꡬννλλ‘ ν΄μ λ¬Έμ λ₯Ό ν΄κ²°νλ€. Context μ λ΄λΆ νλμ Strategy λ₯Ό μ£Όμ ν΄μ μ¬μ©νλ€. μμμ΄ μλλΌ μμμΌλ‘ λ¬Έμ λ₯Ό ν΄κ²°νλ€.
β Context μ λ΄λΆμ Strategy λ₯Ό λκ³ μ¬μ©νλ λ°©μ
Context μ Strategy λ₯Ό νλ² μ‘°λ¦½νκ³ λλ©΄ μ΄νλ‘λ Context λ₯Ό μ€ννκΈ°λ§ νλ©΄ λλ€. μ€νλ§μΌλ‘ μ΄ν리μΌμ΄μ μ κ°λ°ν λ λ‘λ©λλ μμ μ νμν μμ‘΄κ΄κ³λ₯Ό μ£Όμ ν΄λκ³ μ€μ μμ²μ μ²λ¦¬νλ κ²κ³Ό κ°μ μ리μ΄λ€.
λ¨μ μ Context μ Strategy λ₯Ό 쑰립ν μ΄νμλ μ λ΅μ λ³κ²½νκΈ°κ° λ²κ±°λ‘λ€λ μ μ΄λ€. Context μ setter λ₯Ό λ§λ€μ΄ Strategy λ₯Ό λ겨 λ³κ²½νλ©΄ λμ§λ§, Context λ₯Ό μ±κΈν€μΌλ‘ μ¬μ©νλ©΄ λμμ± μ΄μλ±μ λ¬Έμ κ° λ°μν μ μλ€.
κ·Έλμ μ λ΅μ μ€μκ°μΌλ‘ λ³κ²½ν΄μΌ νλ©΄ μ°¨λΌλ¦¬ Context λ₯Ό νλ λ μμ±ν΄μ λ€λ₯Έ Strategy λ₯Ό μ£Όμ νλ κ²μ΄ λ λμ μ νμ΄ λ μ μλ€.
μ°Έκ³
ν€λ νΌμ€νΈ λμμΈ ν¨ν΄ (Head First Design Patterns) - μλ¦ ν리먼,μ리μλ² μ€ λ‘μ¨,μΌμ΄μ μμλΌ,λ²νΈ λ² μ΄μΈ