...


Strategy Pattern
μ λ΅ ν¨ν΄μ μ€ν(λ°νμ) μ€μ μκ³ λ¦¬μ¦ μ λ΅μ μ ννμ¬ κ°μ²΄ λμμ μ€μκ°μΌλ‘ λ°λλλ‘ ν μ μκ² νλ νμ λμμΈ ν¨ν΄ μ΄λ€.
μ¬κΈ°μ 'μ λ΅'μ΄λ μΌμ’ μ μκ³ λ¦¬μ¦μ΄ λ μ λ μμΌλ©°, κΈ°λ₯μ΄λ λμμ΄ λ μλ μλ νΉμ ν λͺ©νλ₯Ό μννκΈ° μν νλ κ³νμ λ§νλ€.
μ¦, μ΄λ€ μΌμ μννλ μκ³ λ¦¬μ¦μ΄ μ¬λ¬κ°μ§ μΌλ, λμλ€μ 미리 μ λ΅μΌλ‘ μ μν¨μΌλ‘μ¨ μμ½κ² μ λ΅μ κ΅μ²΄ν μ μλ, μκ³ λ¦¬μ¦ λ³νμ΄ λΉλ²νκ² νμν κ²½μ°μ μ ν©ν ν¨ν΄μ΄λ€.
μ λ΅ ν¨ν΄ ꡬ쑰

- μ λ΅ μκ³ λ¦¬μ¦ κ°μ²΄λ€ : μκ³ λ¦¬μ¦, νμ, λμμ κ°μ²΄λ‘ μ μν ꡬν체
- μ λ΅ μΈν°νμ΄μ€ : λͺ¨λ μ λ΅ κ΅¬νμ μ λν κ³΅μ© μΈν°νμ΄μ€
- 컨ν μ€νΈ(Context) : μκ³ λ¦¬μ¦μ μ€νν΄μΌ ν λλ§λ€ ν΄λΉ μκ³ λ¦¬μ¦κ³Ό μ°κ²°λ μ λ΅ κ°μ²΄μ λ©μλλ₯Ό νΈμΆ.
- ν΄λΌμ΄μΈνΈ : νΉμ μ λ΅ κ°μ²΄λ₯Ό 컨ν μ€νΈμ μ λ¬ ν¨μΌλ‘μ¨ μ λ΅μ λ±λ‘νκ±°λ λ³κ²½νμ¬ μ λ΅ μκ³ λ¦¬μ¦μ μ€νν κ²°κ³Όλ₯Ό λλ¦°λ€.
νλ‘κ·Έλλ°μμμ β컨ν μ€νΈ(Context) λ μ½ν μΈ (Contetns)λ₯Ό λ΄λ κ·Έ 무μμΈκ°λ₯Ό λ»νλ©°, μ΄λ€ κ°μ²΄λ₯Ό νΈλ€λ§ νκΈ° μν μ κ·Ό μλ¨μ΄λ€.
μ¦, λ¬Όμ»΅μ λ¬Όμ΄ λ΄κ²¨μμΌλ©΄ λ¬Όμ μ½ν μΈ κ° λκ³ , λ¬Όμ»΅μ 컨ν μ€νΈκ° λλ©°, λ¬Όμ νΈλ€λ§ νκΈ° μν μ κ·Ό μλ¨μ΄ λλ€.
μ λ΅ ν¨ν΄μ OOPμ μ§ν©μ²΄
GoFμ λμμΈ ν¨ν΄ μ± μμλ μ λ΅ ν¨ν΄μ λ€μκ³Ό κ°μ΄ μ μνλ€.
- λμΌ κ³μ΄μ μκ³ λ¦¬μ¦κ΅°μ μ μνκ³
- κ°κ°μ μκ³ λ¦¬μ¦μ μΊ‘μννμ¬
- μ΄λ€μ μνΈ κ΅νμ΄ κ°λ₯νλλ‘ λ§λ λ€.
- μκ³ λ¦¬μ¦μ μ¬μ©νλ ν΄λΌμ΄μΈνΈμ μκ΄μμ΄ λ 립μ μΌλ‘
- μκ³ λ¦¬μ¦μ λ€μνκ² λ³κ²½ν μ μκ² νλ€.
λ¬΄μ¨ λ Όλ¬ΈκΈ κ°μ΄ μ€λͺ λμ΄ μμ΄ λκ² μ¬μ€νκ³ λλκ° λμ ν¨ν΄μΈμ€μ μκ² μ§λ§, μ¬μ€ μ λ΅ ν¨ν΄μ μ°λ¦¬κ° μ§κΈκΉμ§ μλ° μΈμ΄λ₯Ό 곡λΆνλ©΄μ λ°°μ΄ μ¬λ¬ κ°μ²΄ μ§ν₯ λ¬Έλ² κΈ°λ²λ€μΈ, SOLID μμΉμ OCP μμΉ, DIP μμΉκ³Ό ν©μ±(compositoin), λ€νμ±(polymorphism), μΊ‘μν(encapsulation) λ± OOP κΈ°μ λ€μ μ΄ μ§ν© λ²μ μ΄λΌκ³ 보면 λλ€.

λ°λΌμ μμ μ λ΅ ν¨ν΄μ μ μλ₯Ό λ€μκ³Ό κ°μ΄ λΉλμ΄ μ€λͺ νλ©΄ μ΄ν΄νκΈ° μ¬μΈ κ²μ΄λ€.
- λμΌ κ³μ΄μ μκ³ λ¦¬μ¦κ΅°μ μ μνκ³ β μ λ΅ κ΅¬νμ²΄λ‘ μ μ
- κ°κ°μ μκ³ λ¦¬μ¦μ μΊ‘μννμ¬ β μΈν°νμ΄μ€λ‘ μΆμν
- μ΄λ€μ μνΈ κ΅νμ΄ κ°λ₯νλλ‘ λ§λ λ€. β ν©μ±(composition)μΌλ‘ ꡬμ±
- μκ³ λ¦¬μ¦μ μ¬μ©νλ ν΄λΌμ΄μΈνΈμ μκ΄μμ΄ λ 립μ μΌλ‘ β 컨ν μ€νΈ κ°μ²΄ μμ μμ΄
- μκ³ λ¦¬μ¦μ λ€μνκ² λ³κ²½ν μ μκ² νλ€. β λ©μλλ₯Ό ν΅ν΄ μ λ΅ κ°μ²΄λ₯Ό μ€μκ°μΌλ‘ λ³κ²½ν¨μΌλ‘μ¨ μ λ΅μ λ³κ²½
μ λ΅ ν¨ν΄ νλ¦
ν΄λμ€ κ΅¬μ±

// μ λ΅(μΆμνλ μκ³ λ¦¬μ¦)
interface IStrategy {
void doSomething();
}
// μ λ΅ μκ³ λ¦¬μ¦ A
class ConcreteStrateyA implements IStrategy {
public void doSomething() {}
}
// μ λ΅ μκ³ λ¦¬μ¦ B
class ConcreteStrateyB implements IStrategy {
public void doSomething() {}
}
// 컨ν
μ€νΈ(μ λ΅ λ±λ‘/μ€ν)
class Context {
IStrategy Strategy; // μ λ΅ μΈν°νμ΄μ€λ₯Ό ν©μ±(composition)
// μ λ΅ κ΅μ²΄ λ©μλ
void setStrategy(IStrategy Strategy) {
this.Strategy = Strategy;
}
// μ λ΅ μ€ν λ©μλ
void doSomething() {
this.Strategy.doSomething();
}
}
ν΄λμ€ νλ¦

// ν΄λΌμ΄μΈνΈ(μ λ΅ κ΅μ²΄/μ λ΅ μ€νν κ²°κ³Όλ₯Ό μ»μ)
class Client {
public static void main(String[] args) {
// 1. 컨ν
μ€νΈ μμ±
Context c = new Context();
// 2. μ λ΅ μ€μ
c.setStrategy(new ConcreteStrateyA());
// 3. μ λ΅ μ€ν
c.doSomething();
// 4. λ€λ₯Έ μ λ΅ μ€μ
c.setStrategy(new ConcreteStrateyB());
// 5. λ€λ₯Έ μ λ΅ μν
c.doSomething();
}
}
μ λ΅ ν¨ν΄ νΉμ§
μ λ΅ ν¨ν΄ μ¬μ© μκΈ°
- μ λ΅ μκ³ λ¦¬μ¦μ μ¬λ¬ λ²μ λλ λ³νμ΄ νμν λ ν΄λμ€νλ₯Ό ν΅ν΄ κ΄λ¦¬
- μκ³ λ¦¬μ¦ μ½λκ° λ ΈμΆλμ΄μλ μ λλ λ°μ΄ν°μ μ‘μΈμ€ νκ±°λ λ°μ΄ν°λ₯Ό νμ©ν λ (μΊ‘μν)
- μκ³ λ¦¬μ¦μ λμμ΄ λ°νμμ μ€μκ°μΌλ‘ κ΅μ²΄ λμ΄μΌ ν λ
μ λ΅ ν¨ν΄ μ£Όμμ
- μκ³ λ¦¬μ¦μ΄ λ§μμ§μλ‘ κ΄λ¦¬ν΄μΌν κ°μ²΄μ μκ° λμ΄λλ€λ λ¨μ μ΄ μλ€.
- λ§μΌ μ΄ν리μΌμ΄μ νΉμ±μ΄ μκ³ λ¦¬μ¦μ΄ λ§μ§ μκ³ μμ£Ό λ³κ²½λμ§ μλλ€λ©΄, μλ‘μ΄ ν΄λμ€μ μΈν°νμ΄μ€λ₯Ό λ§λ€μ΄ νλ‘κ·Έλ¨μ 볡μ‘νκ² λ§λ€ μ΄μ κ° μλ€.
- κ°λ°μλ μ μ ν μ λ΅μ μ ννκΈ° μν΄ μ λ΅ κ°μ μ°¨μ΄μ μ νμ νκ³ μμ΄μΌ νλ€. (볡μ‘λ β)
μμ λ₯Ό ν΅ν΄ μμ보λ Strategy ν¨ν΄
RPG κ²μμμ μΊλ¦ν°μ 무기 μ λ΅
μ€μ λ‘ κ²μμμ μ΄λ°μμΌλ‘ λμ΄μμ§λ μμ§λ§, κ·Έλλ 첫λ²μ§Έ μμ μΈ λ§νΌ μ¬λ―Έμκ² λ μλ€μκ² λ€κ°κ°κΈ° μν΄μ RPG κ²μμ μμλ‘ λ€μ΄λ³΄μλ€.
μ΄ ν¨ν΄ ꡬν μμ μ 컨μ μ μ μ νΉμ±μ λ°λΌ μ£ΌμΈκ³΅μ΄ 무기 μ λ΅μ λ°κΏκ°λ©° λμνλ κ²μ΄λ€.
ν΄λ¦°νμ§ μμ λ¬Έμ μ μ½λ β
μλ μ½λλ₯Ό μ¬λ Ύλ³΄λ©΄ state 맀κ°λ³μμ κ°μ λ°λΌμ κ°μ μ μΌλ‘ attack() ν¨μμ λμμ μ μ΄νλλ‘ λμ΄ μλ€. μ μ΄ μ€λ©΄ μμλ₯Ό λ©μλμ λ겨 쑰건문μΌλ‘ μΌμΌν νν°λ§νμ¬ μ μ ν μ λ΅μ μ€ννμλ€.
νμ§λ§ μν λ³μλ₯Ό ν΅ν΄ νμλ₯Ό λΆκΈ°λ¬ΈμΌλ‘ λλλ νμλ μ’μ§ μμ μ½λμ΄λ€. μμΉ« μλͺ»νλ©΄ if else μ§μ₯μ λΉ μ§ μ μκΈ° λλ¬Έμ΄λ€.
class TakeWeapon {
public static final int SWORD = 0;
public static final int SHIELD = 1;
public static final int CROSSBOW = 2;
private int state;
void setWeapon(int state) {
this.state = state;
}
void attack() {
if (state == SWORD) {
System.out.println("μΉΌμ νλλ₯΄λ€");
} else if (state == SHIELD) {
System.out.println("λ°©ν¨λ‘ λ°μΉλ€");
} else if (state == CROSSBOW) {
System.out.println("μκΆμ λ°μ¬νλ€");
}
}
}
class User {
public static void main(String[] args) {
// νλ μ΄μ΄ μμ 무기 μ°©μ© μ λ΅μ μ€μ
TakeWeapon hand = new TakeWeapon();
// νλ μ΄μ΄κ° κ²μ λ€λλ‘ μ λ΅ μ€μ
hand.setWeapon(TakeWeapon.SWORD);
hand.attack(); // "μΉΌμ νλλ₯΄λ€"
// νλ μ΄μ΄κ° λ°©ν¨λ₯Ό λ€λλ‘ μ λ΅ μ€μ
hand.setWeapon(TakeWeapon.SHIELD);
hand.attack(); // "λ°©ν¨λ‘ λ°μΉλ€"
}
}
μ λ΅ ν¨ν΄μ μ μ©ν μ½λ βοΈ
μμ ν΄λ¦°νμ§ μμ μ½λλ₯Ό ν΄κ²°νλ κ°μ₯ μ’μ λ°©λ²μ λ³κ²½μν€κ³ μ νλ νμ(μ λ΅)λ₯Ό μ§μ λ겨주λ κ²μ΄λ€.
μ°μ μ¬λ¬ 무기λ€μ κ°μ²΄ ꡬνμ²΄λ‘ μ μνκ³ μ΄λ€μ Weaponμ΄λΌλ μΈν°νμ΄μ€λ‘ λ¬Άμ΄ μ£Όμλ€. κ·Έλ¦¬κ³ μΈν°νμ΄μ€λ₯Ό 컨ν
μ€νΈ ν΄λμ€μ ν©μ±(composition) μν€κ³ , setWeapon() λ©μλλ₯Ό ν΅ν΄ μ λ΅ μΈν°νμ΄μ€ κ°μ²΄μ μνλ₯Ό λ°λ‘λ°λ‘ λ³κ²½ν μ μλλ‘ κ΅¬μ± νμλ€.

// μ λ΅ - μΆμνλ μκ³ λ¦¬μ¦
interface Weapon {
void offensive();
}
class Sword implements Weapon {
@Override
public void offensive() {
System.out.println("μΉΌμ νλλ₯΄λ€");
}
}
class Shield implements Weapon {
@Override
public void offensive() {
System.out.println("λ°©ν¨λ‘ λ°μΉλ€");
}
}
class CrossBow implements Weapon {
@Override
public void offensive() {
System.out.println("μκΆμ λ°μ¬νλ€");
}
}
// 컨ν
μ€νΈ - μ λ΅μ λ±λ‘νκ³ μ€ν
class TakeWeaponStrategy {
Weapon wp;
void setWeapon(Weapon wp) {
this.wp = wp;
}
void attack() {
wp.offensive();
}
}
// ν΄λΌμ΄μΈνΈ - μ λ΅ μ 곡/μ€μ
class User {
public static void main(String[] args) {
// νλ μ΄μ΄ μμ 무기 μ°©μ© μ λ΅μ μ€μ
TakeWeaponStrategy hand = new TakeWeaponStrategy();
// νλ μ΄μ΄κ° κ²μ λ€λλ‘ μ λ΅ μ€μ
hand.setWeapon(new Sword());
hand.attack(); // "μΉΌμ νλλ₯΄λ€"
// νλ μ΄μ΄κ° λ°©ν¨λ₯Ό λ€λλ‘ μ λ΅ λ³κ²½
hand.setWeapon(new Shield());
hand.attack(); // "λ°©ν¨λ‘ λ°μΉλ€"
// νλ μ΄μ΄κ° μκΆμ λ€λλ‘ μ λ΅ λ³κ²½
hand.setWeapon(new Crossbow());
hand.attack(); // "μκΆμ λ°μ¬νλ€"
}
}
ν΄λ¦°νμ§ μλ μ½λμμλ λ©μλμ μμκ°μ λ겨주μμ§λ§, μ λ΅ ν¨ν΄μμ μΈμ€ν΄μ€λ₯Ό λ£μ΄ μκ³ λ¦¬μ¦μ μννλλ‘ ν κ²μ΄λ€.
μ΄λ°μμΌλ‘ ꡬμ±νλ©΄ μ’μ μ μ λμ€μ μΉΌμ΄λ λ°©ν¨μΈμ λλΌλ μ°½κ³Ό κ°μ μ λ΅ λ¬΄κΈ°λ€μ μΆκ°λ‘ λ±λ‘ν λ, μ½λμ μμ μμ΄ λΉ λ₯΄κ² κΈ°λ₯μ νμ₯ν μ μλ€λ μ₯μ μ΄ μλ€. (ν΄λμ€λ₯Ό μΆκ°νκ³ implements ν΄μ£Όλ©΄ λ)
κ²°κ΅ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μ ν΅μ¬μΈ μ μ§λ³΄μλ₯Ό μ©μ΄νκ² νκΈ°μν΄, μ½κ° 볡μ‘νλλΌλ μ΄λ¬ν ν¨ν΄μ μ μ©νμ¬ νλ‘κ·Έλ¨μ ꡬμ±ν΄ λκ°λ κ²μ΄λ€.
μ¬λ¬ κΈ°λ₯ μ λ΅μ κ°μ§ λ‘λ΄
ν΄λ¦°νμ§ μμ λ¬Έμ μ μ½λ β
λ€μκ³Ό κ°μ΄ Robotμ΄λΌλ μΆμ ν΄λμ€κ° μκ³ μ΄λ₯Ό μμνλ κ±·λ λ‘λ΄(WalingRobot), λ°λ λ‘λ΄(RunningRobot) μΌλ‘ ꡬμ±λ κ°μ²΄κ° μλ€.

public abstract class Robot {
public abstract void display();
public abstract void move();
}
class WalkingRobot extends Robot {
public void display() {
System.out.println("κ±·κΈ° λ‘λ΄");
}
public void move() {
System.out.println("κ±Έμ΄μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
}
class RunningRobot extends Robot {
public void display() {
System.out.println("λ¬λ¦¬λ λ‘λ΄");
}
public void move() {
System.out.println("λ°μ΄μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
}
class Main {
public static void main(String[] args) {
Robot robot1 = new WalkingRobot();
robot1.display();
robot1.move();
Robot robot2 = new RunningRobot();
robot2.display();
robot2.move();
}
}
보기μλ κ°μ²΄ μ§ν₯μ μΈ λ¬Έμ μλ μ½λμ΄μ§λ§, λ§μΌ κ³ κ°μΌλ‘λΆν° λ‘λ΄μ κΈ°λ₯ μΆκ°λ₯Ό μμ²λ°μμλ μ½λμ μ μ§ λ³΄μ λ©΄μμ λ¬Έμ κ° λ°μνλ€.
μλ₯Όλ€μ΄ λ‘λ΄μ λ²μ κΈ°λ₯λ μΆκ°νλ€κ³ κ°μ νλ€λ©΄ translate() λ©μλλ₯Ό κ°κ±·λ λ‘λ΄(WalingRobot), λ°λ λ‘λ΄(RunningRobot)μ μΆκ°νμ¬μΌ νλ€. κ·Έλμ μΆμν ꡬ쑰μ λ§κ² Robot μΆμ ν΄λμ€μ λ©μλλ₯Ό μΆκ°νκ³ κ°κΈ° κΈ°λ₯μ μλ§κ² νλ λ‘λ΄ ν΄λμ€λ₯Ό λΆλ¦¬νμ¬ κ΅¬ννλ μμ λ‘λ΄ ν΄λμ€κ° λλ°°λ‘ λμ΄λ λ²λ Έλ€.
μ¬κΈ°μ λ κΈ°λ₯μ μΆκ°νλ©΄ μ΄λ²μ ν΄λμ€κ° 8κ°λ‘ λΆμ΄λ κ²μ΄λ€. κ·ΈλΏλ§ μλλΌ μ΄λ νλμ κΈ°λ₯ move() λ©μλ μ€νμ λ³κ²½ν΄μΌ λλ€λ©΄ μ 체 μμ ν΄λμ€μ λ±λ‘ λμ΄μλ move() λ©μλλ₯Ό μΌμΌν λ€μ Έ μμ ν΄μΌ ν κ²μ΄λ€.

public abstract class Robot {
public abstract void display();
public abstract void move();
public abstract void translate(); // λ²μ λ©μλ νλλ₯Ό μΆκ°νμ λΏμΈλ°
}
// --- ν΄λμ€ κ°―μκ° λλ°°λ‘ λμ΄λ λ²λ Έλ€ !!
class KoreanWalkingRobot extends Robot {
public void display() {
System.out.println("κ±·κΈ° λ‘λ΄");
}
public void move() {
System.out.println("κ±Έμ΄μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
public void translate() {
System.out.println("νκ΅μ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
");
}
}
class KoreanRunningRobot extends Robot {
public void display() {
System.out.println("λ¬λ¦¬λ λ‘λ΄");
}
public void move() {
System.out.println("λ°μ΄μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
public void translate() {
System.out.println("νκ΅μ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
");
}
}
class JapaneseWalkingRobot extends Robot {
public void display() {
System.out.println("κ±·κΈ° λ‘λ΄");
}
public void move() {
System.out.println("κ±Έμ΄μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
public void translate() {
System.out.println("μΌλ³Έμ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
");
}
}
class JapaneseRunningRobot extends Robot {
public void display() {
System.out.println("λ¬λ¦¬λ λ‘λ΄");
}
public void move() {
System.out.println("λ°μ΄μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
public void translate() {
System.out.println("μΌλ³Έμ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
");
}
}
μ λ΅ ν¨ν΄μ μ μ©ν μ½λ βοΈ
μμ κ°μ 'ν΄λμ€ νλ°' λ¬Έμ κ° μΌμ΄λ μ΄μ λ κ°μ²΄λ₯Ό μ¬λ¬Ό / μλ¬Ό μ λλ‘ λ°μ μΈμνμ§ λͺ»ν΄μ μ΄λ€.
κ°μ²΄λ νλμ κΈ°λ₯μ΄λ νμ, λμμΌλ‘λ ννν μ μλ€. μ λ΅ ν¨ν΄μ μ΄λ¬ν μ κ·ΌμΌλ‘ 볡μ‘ν λ¬Έμ λ₯Ό ν΄κ²°ν΄ λκ°λ μμ΄λ€.
μλ₯Ό λ€μ΄ λ‘λ΄ ν΄λμ€κ° μκ³ μλΉνλ λμ λ©μλκ° μλ€λ©΄, μ΄ μλΉ λ©μλλ₯Ό λ‘λ΄ μ¬λ¬Ό κ°μ²΄μ κ΅νλκ² νλκ² μλλΌ, λ°λ‘ νμ ꡬνμ²΄λ‘ λΉΌμ μ μνκ³ κ΄λ¦¬νλ κ²μ΄λ€. κ·Έλ¦¬κ³ μ΄ νμ κ°μ²΄λ€μ λͺ¨μ μΈν°νμ΄μ€λ‘ λ¬Άμ΄ νλμ μ λ΅ λ¬Άμμ ꡬμ±νκ³ , μ΄κ²μ 컨ν μ€νΈμ ν©μ±μμΌ λ€νμ±μ ν΅ν΄ μ κΈ°μ μΌλ‘ μ¬λ¬ μ λ΅ νμλ€μ μ¬μ©ν μ μλλ‘ νλ κ²μ΄λ€.
κ·Έλμ λ§λ€κ³ μ νλ μ¬λ¬ΌμΈ λ‘λ΄ ν΄λμ€λ νλμ΄κ³ , λ‘λ΄μ μλ‘ λ€λ₯Έ λ€μν μ λ΅ κ°μ²΄λ€μ μ μ© μν΄μΌλ‘μ¨ κ°κΈ° λ€λ₯Έ μ λ΅μ μννλ λ‘λ΄λ€μ μ¬λ¬κ° λ§λ€κ±°λ νΉμ νλμ λ‘λ΄μ κ°μ§κ³ μ¬λ¬κ°μ§ μ λ΅μ μ€μμΉνμ¬ μ€νν μ μκ² νλ κ²μ΄λ€.

// Run / Walk μ λ΅(μΆμνλ μκ³ λ¦¬μ¦)
interface MoveStrategy {
void move();
}
class Walk implements MoveStrategy {
public void move() {
System.out.println("κ±Έμ΄μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
}
class Run implements MoveStrategy {
public void move() {
System.out.println("λ°λ¬μ λ°°λ¬ν©λλ€ μ-λΉ
");
}
}
// νκ΅μ΄ / μΌλ³Έμ΄ λ²μ μ λ΅(μΆμνλ μκ³ λ¦¬μ¦)
interface TranslateStrategy {
void translate();
}
class Korean implements TranslateStrategy {
public void translate() {
System.out.println("νκ΅μ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
");
}
}
class Japanese implements TranslateStrategy {
public void translate() {
System.out.println("μΌλ³Έμ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
");
}
}
// 컨ν
μ€νΈ(μ λ΅ λ±λ‘/μ€ν)
public class Robot {
MoveStrategy moveStrategy;
TranslateStrategy translateStrategy;
Robot(MoveStrategy moveStrategy, TranslateStrategy translateStrategy) {
this.moveStrategy = moveStrategy;
this.translateStrategy = translateStrategy;
}
void move() {
moveStrategy.move();
}
void translate() {
translateStrategy.translate();
}
void setMove(MoveStrategy moveStrategy) {
this.moveStrategy = moveStrategy;
}
void setTranslate(TranslateStrategy translateStrategy) {
this.translateStrategy = translateStrategy;
}
}
// ν΄λΌμ΄μΈνΈ(μ λ΅ κ΅μ²΄/μ λ΅ μ€νν κ²°κ³Όλ₯Ό μ»μ)
class User {
public static void main(String[] args) {
Robot robot = new Robot(new Walk(), new Korean());
robot.move(); // κ±Έμ΄μ λ°°λ¬ν©λλ€ μ-λΉ
robot.translate(); // νκ΅μ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
// λ‘λ΄μ μ λ΅(κΈ°λ₯)μ runκ³Ό Japanese λ²μμΌλ‘ λ³κ²½
robot.setMove(new Run());
robot.setTranslate(new Japanese());
robot.move(); // λ°λ¬μ λ°°λ¬ν©λλ€ μ-λΉ
robot.translate(); // μΌλ³Έμ΄λ‘ λ²μν©λλ€ μ-λΉ-λΉ
}
}
μΉ΄λ κ²°μ μ λ΅ μμ€ν
μ΄λ²μλ μ’λ μ€λ¬΄μμ μ¬μ©νλ μ λ΅ ν¨ν΄ μμ λ₯Ό κ°μ Έμ 보μλ€.
λ€μ μμ λ μΌν μΉ΄νΈμ μμ΄ν μ λ΄μ LUNA μ μ©μΉ΄λ λλ KAKAO μ μ©μΉ΄λλΌλ λ κ°μ μ λ΅μ μ΄μ©ν΄ μν©μ λ°λΌ κ²°μ λ₯Ό μ§ννλ€λ 컨μ μ΄λ€.
μ΄λ² μμ μ μμ μμ κ°μ λ€λ₯Έμ μ μ λ΅ μΈν°νμ΄μ€μΈ PaymentStrategyλ₯Ό ν΄λμ€ νλλ‘ ν©μ±(composition) νμ§ μκ³ μ»¨ν
μ€νΈμ pay() λ©μλμ 맀κ°λ³μλ‘ ν©μ±(composition) νλ€λ μ°¨μ΄κ° μλ€.

// μ λ΅ - μΆμνλ μκ³ λ¦¬μ¦
interface PaymentStrategy {
void pay(int amount);
}
class KAKAOCardStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public KAKAOCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
this.name = nm;
this.cardNumber = ccNum;
this.cvv = cvv;
this.dateOfExpiry = expiryDate;
}
@Override
public void pay(int amount) {
System.out.println(amount + "μ paid using KAKAOCard.");
}
}
class LUNACardStrategy implements PaymentStrategy {
private String emailId;
private String password;
public LUNACardStrategy(String email, String pwd) {
this.emailId = email;
this.password = pwd;
}
@Override
public void pay(int amount) {
System.out.println(amount + "μ paid using LUNACard.");
}
}
// 컨ν
μ€νΈ - μ λ΅μ λ±λ‘νκ³ μ€ν
class ShoppingCart {
List<Item> items;
public ShoppingCart() {
this.items = new ArrayList<Item>();
}
public void addItem(Item item) {
this.items.add(item);
}
// μ λ΅μ 맀κ°λ³μλ‘ λ°μμ λ°λ‘λ°λ‘ μ λ΅μ μ€ν
public void pay(PaymentStrategy paymentMethod) {
int amount = 0;
for (Item item : items) {
amount += item.price;
}
paymentMethod.pay(amount);
}
}
class Item {
public String name;
public int price;
public Item(String name, int cost) {
this.name = name;
this.price = cost;
}
}
// ν΄λΌμ΄μΈνΈ - μ λ΅ μ 곡/μ€μ
class User {
public static void main(String[] args) {
// μΌνμΉ΄νΈ μ λ΅ μ»¨ν
μ€νΈ λ±λ‘
ShoppingCart cart = new ShoppingCart();
// μΌν λ¬Όν
Item A = new Item("λ§₯λΆ νλ‘", 10000);
Item B = new Item("νλ μ΄μ€ν
μ΄μ
", 30000);
cart.addItem(A);
cart.addItem(B);
// LUNACardλ‘ κ²°μ μ λ΅ μ€ν
cart.pay(new LUNACardStrategy("kundol@example.com", "pukubababo")); // 4000μ paid using LUNACard.
// KAKAOBankλ‘ κ²°μ μ λ΅ μ€ν
cart.pay(new KAKAOCardStrategy("Ju hongchul", "123456789", "123", "12/01")); // 4000μ paid using KAKAOCard.
}
}
λ©μλμ μ λ ₯κ°μΌλ‘ κ°μ²΄λ₯Ό ν λΉνλ λ°©μμ΄ μ’μ μ μ, κ° μ λ΅μ λ°λΌ μ΄κΈ°ννλ μμ±μ 맀κ°λ³μ κ°―μκ° λ€λ₯Ό μ μκΈ° λλ¬Έμ΄λ€.
μλ₯Όλ€μ΄ LUNAμΉ΄λλ λ©μΌκ³Ό λΉλ°λ²νΈλ§ νμνμ§λ§, KAKAOμΉ΄λλ νμ¬ μ μ± μ λ°λΌ μ¬λ¬κ°μ§ μ 보λ€μ΄ λ νμν μ μκΈ° λλ¬Έμ΄λ€.
μ€λ¬΄μμ μ°Ύμ보λ Strategy ν¨ν΄
Java
- Collectionsμ
sort()λ©μλμ μν΄ κ΅¬νλλcompare()λ©μλμ μ΄μ© - javax.servlet.http.HttpServletμμ
service()λ©μλμ λͺ¨λdoXXX()λ©μλμ μ΄μ© - javax.servlet.Filterμ
doFilter()λ©μλμ μ΄μ©
Comparator
μ¬μ€ μλ°μμ μ΅λͺ ν΄λμ€λ‘ ꡬν체λ₯Ό κ·Έλκ·Έλ μ μνκ³ μμ λμ λ©μλμ λ‘μ§μ κ·Έλκ·Έλ λ§λ€μ΄ ν λΉνλ λ°©μλ μΌμ’ μ μ λ΅μ μ€μκ°μΌλ‘ λ³κ²½νμ¬ μ§μ νλ ν¨ν΄κ³Ό λ§μ΄ μ μ¬νλ€κ³ λ³Ό μ μλ€.
class StrategyInJava {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(2);
numbers.add(1);
numbers.add(3);
numbers.add(5);
numbers.add(4);
// sort λ©μλμ 맀κ°λ³μλ‘ μ΅λͺ
ν΄λμ€λ‘ Comparator κ°μ²΄λ₯Ό μΈμ€ν΄μ€ννμ¬
// κ·Έ μμ compare λ©μλ λμ λ‘μ§(ConcreteStrategy)λ₯Ό μ§μ ꡬννμ¬ ν λΉνλ κ²μ λ³Ό μ μλ€.
Collections.sort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(numbers);
}
}


Spring Framework
public class StrategyInSpring {
public static void main(String[] args) {
// κ°κ°μ μ€μ μ λ°λΌ λλ μ§ ApplicationContext λ€
ApplicationContext applicationContext = new ClassPathXmlApplicationContext();
ApplicationContext applicationContext1 = new FileSystemXmlApplicationContext();
ApplicationContext applicationContext2 = new AnnotationConfigApplicationContext();
BeanDefinitionParser parser;
PlatformTransactionManager platformTransactionManager; // λ€μν νΈλμμ
λ©λμ λ₯Ό μ 곡νλ€
CacheManager cacheManager; // λ€μν μΊμ μ λ΅μ μ 곡
}
}
Node.js
μ΄λΆλΆμ λ Έλλ₯Ό λ€λ£¨λ μλ°μ€ν¬λ¦½νΈ κ°λ°μλ€μ μν μμμ΄λ€. λμμΈ ν¨ν΄μ κΌ μλ°(java) νλ‘κ·Έλλ° μΈμ΄μλ§ μ μ©λλ μ¬λ‘κ° μλμ 보μ¬μ£ΌκΈ° μν΄ λ£μ΄λ³΄μλ€.
Passport λΌμ΄λΈλ¬λ¦¬
passport.js λΌμ΄λΈλ¬λ¦¬λ λ€μ΄λ², μΉ΄μΉ΄μ€, νμ΄μ€λΆ λ‘κ·ΈμΈκ³Ό κ°μ OAuth λ‘κ·ΈμΈμ ꡬνν λ μ¬μ©λλ μμ£Ό μ λͺ ν μλ°μ€ν¬λ¦½νΈ λΌμ΄λΈλ¬λ¦¬ μ΄λ€. κ·Έλ¦¬κ³ μ΄ passport.jsκ° λ°λ‘ μ λ΅ ν¨ν΄μΌλ‘ κ΅¬μ± λμ΄ μλ€.
μλ μ½λλ₯Ό 보면 μμ μλ―μ΄, passport.use(new SNSStrategy(), ...) μ²λΌ passport.use()λΌλ λ©μλμ μ
λ ₯κ°μΌλ‘ μ λ΅ κ°μ²΄λ₯Ό λ§λ€μ΄ λ‘μ§μ μννλ κ²μ λ³Ό μ μλ€.
μμ§ μ λ΅ ν¨ν΄μ λ°°μ°κΈ°μ μ μ λ³μλͺ μ Strategy λΌκ³ λͺ λͺ νλμ§ λͺ°λμλλ°, μ΄μ ν¨ν΄μ λ°°μ°κ³ λλ μλΉν ꡬ쑰μ μΌλ‘ μ§μ¬μλ€λ κ²μ λλ μ μμ κ²μ΄λ€.
const passport = require('passport'); // passport.jsμ κ°μ²΄ κ°μ Έμ€κΈ°
const KakaoStrategy = require('passport-kakao').Strategy;
const NaverStrategy = require('passport-naver-v2').Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;
// μΉ΄μΉ΄μ€ λ‘κ·ΈμΈ μ λ΅ λ±λ‘
passport.use(new KakaoStrategy({ clientID, callbackURL }, async (accessToken, refreshToken, profile, done) => {
// ...
});
// λ€μ΄λ² λ‘κ·ΈμΈ μ λ΅ λ±λ‘
passport.use(new NaverStrategy({ clientID, clientSecret, callbackURL }, async (accessToken, refreshToken, profile, done) => {
// ...
});
// κ΅¬κΈ λ‘κ·ΈμΈ μ λ΅ λ±λ‘
passport.use(new GoogleStrategy({ clientID, clientSecret, callbackURL }, async (accessToken, refreshToken, profile, done) => {
// ...
});
λΉμ·ν λμμΈ ν¨ν΄ λΉκ΅
Strategy vs Temaplate Method
ν¨ν΄ μ μ¬μ
- μ λ΅ ν¨ν΄κ³Ό ν νλ¦Ώ λ©μλ ν¨ν΄μ μκ³ λ¦¬μ¦μ λμ λ°λΌ μ μ©νλ€λ 컨μ μΌλ‘μ¨, λμ΄ κ³΅ν΅μ μ κ°μ§κ³ μλ€.
- μ λ΅ λ° ν νλ¦Ώ λ©μλ ν¨ν΄μ κ°λ°©ν νμ μμΉμ μΆ©μ‘±νκ³ μ½λλ₯Ό λ³κ²½νμ§ μκ³ μννΈμ¨μ΄ λͺ¨λμ μ½κ² νμ₯ν μ μλλ‘ νλ λ° μ¬μ©ν μ μλ€.
ν¨ν΄ μ°¨μ΄μ
- μ λ΅ ν¨ν΄μ ν©μ±(composition)μ ν΅ν΄ ν΄κ²°μ± μ κ°κ΅¬νλ©°, ν νλ¦Ώ λ©μλ ν¨ν΄μ μμ(inheritance)μ ν΅ν΄ ν΄κ²°μ± μ μ μνλ€.
- κ·Έλμ μ λ΅ ν¨ν΄μ ν΄λΌμ΄μΈνΈμ κ°μ²΄ κ°μ κ²°ν©μ΄ λμ¨ν λ°λ©΄, ν νλ¦Ώ λ©μλ ν¨ν΄μμλ λ λͺ¨λμ΄ λ λ°μ νκ² κ²°ν©λλ€. (κ²°ν©λκ° λμΌλ©΄ μμ’μ)
- μ λ΅ ν¨ν΄μμλ λλΆλΆ μΈν°νμ΄μ€λ₯Ό μ¬μ©νμ§λ§, ν νλ¦Ώ λ©μλ ν¨ν΄μλ μ£Όλ‘ μΆμ ν΄λμ€λ ꡬ체μ μΈ ν΄λμ€λ₯Ό μ¬μ©νλ€.
- μ λ΅ ν¨ν΄μμλ μ 체 μ λ΅ μκ³ λ¦¬μ¦μ λ³κ²½ν μ μμ§λ§, ν νλ¦Ώ λ©μλ ν¨ν΄μμλ μκ³ λ¦¬μ¦μ μΌλΆλ§ λ³κ²½λκ³ λλ¨Έμ§λ λ³κ²½λμ§ μμ μνλ‘ μ μ§λλ€. (ν νλ¦Ώμ μ’ μ)
- λ°λΌμ λ¨μΌ μμλ§μ΄ κ°λ₯ν μλ°μμ μμ μ νμ΄ μλ ν νλ¦Ώ λ©μλ ν¨ν΄λ³΄λ€λ, λ€μνκ² λ§μ μ λ΅μ implements ν μ μλ μ λ΅ ν¨ν΄μ΄ νμ μμ λ§μ΄ μ¬μ©λλ νΈμ΄λ€.
# μ°Έκ³ μλ£
μ½λ©μΌλ‘ νμ΅νλ GoFμ λμμΈ ν¨ν΄ - λ°±κΈ°μ
https://refactoring.guru/design-patterns/template-method
https://reactiveprogramming.io/blog/en/design-patterns/strategy
https://blog.naver.com/jhc9639/222704238003
https://www.youtube.com/watch?v=vNsZXC3VgUA
μ΄ κΈμ΄ μ’μΌμ ¨λ€λ©΄ ꡬλ & μ’μμ
μ¬λ¬λΆμ ꡬλ
κ³Ό μ’μμλ
μ μμκ² ν° νμ΄ λ©λλ€.