행위를 클래스로 캡슐화해 동적으로 행위를 자유롭게 바꿀 수 있게 해주는 패턴
- 같은 문제를 해결하는 여러 알고리즘이 클래스별로 캡슐화되어 있고 이들이 필요할 때 교체할 수 있도록 함으로써 동일한 문제를 다른 알고리즘으로 해결할 수 있게 하는 디자인 패턴

| Strategy : - 인터페이스나 추상 클래스로 외부에서 동일한 방식으로 알고리즘을 호출하는 방법을 명시 |
| ConcreteStrategy : - 스트래티지 패턴에서 명시한 알고리즘을 실제로 구현한 클래스 |
| Context : - 스트래치지 패턴을 이용하는 역할을 수행한다. - 필요에 따라 동적으로 구체적인 전략을 바꿀 수 있도록 setter 메서드(' 집약관계 ' ) 를 제공한다. |
| 행위 패턴 : - 객체나 클래스 사이의 알고리즘이나 책임 분배에 관련된 패턴 - 한 객체가 혼자 수행할 수 없는 작업을 여러 개의 객체로 어떻게 분배하는지, 또 그렇게 하면서도 객체 사이의 결합도를 최소화하는 것에 중점을 둔다. |
| 집약 관계 : - 참조값을 인자로 받아 필드를 세팅하는 경우 - 전체 객체의 라이프타임과 부분 객체의 라이프 타임은 독립적이다. - 즉, 전체 객체가 메모리에서 사라진다 해도 부분 객체는 사라지지 않는다. |
예를들어, 게임 캐릭터를 만든다고 가정하자.
Robot이라는 수퍼 클래스를 만들고, 이 클래스를 확장하여 다른 로봇 클래스들을 만든다.
각각의 로봇의 모양새는 다르므로 display() 메서드는 추상 메서드로 선언한다.
public abstract class Robot {
public void run() {
System.out.println("run~");
}
public abstract void display();
}
public class RobotA extends Robot {
@Override
public void display() {
System.out.println("A display~");
}
}public class RobotB extends Robot {
@Override
public void display() {
System.out.println("B display~");
}
}
수퍼 클래스 Robot에 fly() 메서드를 추가한다.
수퍼 클래스 Robot을 상속받은 클래스들은 모두 fly() 메서드를 사용할 수 있다.
그러나 fly() 기능이 필요없는 클래스도 fly() 메서드를 사용할 수 있게 된다.
public abstract class Robot {
public void run() {
System.out.println("run~");
}
public void fly() {
System.out.println("fly~");
}
public abstract void display();
}
ARobot 클래스에서는 fly() 기능이 필요하지 않다. 그러므로 오버라이드 하여 처리한다.
* 앞으로 추가적인 클래스들이 생길 때마다 또는 특정 클래스에만 추가적인 기능을 부여할 경우, 일일이 검토하여 구분하여야 한다.
public class RobotA extends Robot {
@Override
public void display() {
System.out.println("A display~");
}
public void fly() {
// 아무것도 하지 않도록 오버라이드
}
}public abstract class Robot {
public abstract void display();
}
인터페이스
public interface Runnable {
void run();
}
public interface Flyable {
void fly();
}
public class RobotA extends Robot implements Runnable{
@Override
public void display() {
System.out.println("A display~");
}
@Override
public void run() {
System.out.println("run~");
}
}
public class RobotB extends Robot implements Runnable, Flyable {
@Override
public void display() {
System.out.println("B display~");
}
@Override
public void fly() {
System.out.println("fly~");
}
@Override
public void run() {
System.out.println("run~");
}
}
다음과 같이 구현한다면 Flyable, Runnable 인터페이스를 일일이 다 구현해주어야 한다.
모든 코드들은 하드코딩하게 되고, 재사용할 수 없게 된다.
1. 달라지는 부분을 분리한다.
2. 구현이 아닌 인터페이스 맞춰서 프로그래밍 한다.
각 행동별 인터페이스를 생성한다.
각각의 구체적인 행동은 인터페이스를 상속받아 구현한다.
Interface MoveBehavior
public interface MoveBehavior {
void move(String name);
}
public class FlyBehavior implements MoveBehavior {
@Override
public void move(String name) {
System.out.println(name+ " fly~");
}
}
public class RunBehavior implements MoveBehavior {
@Override
public void move(String name) {
System.out.println(name + " run ~");
}
}
Interface AttackBehavior
public interface AttackBehavior {
void attack(String name);
}
public class MissileBehavior implements AttackBehavior {
@Override
public void attack(String name) {
System.out.println(name+ " missile ~");
}
}
public class PunchBehavior implements AttackBehavior {
@Override
public void attack(String name) {
System.out.println(name+ " punch ~");
}
}
Abstract Robot
public abstract class Robot {
private String name;
private MoveBehavior moveBehavior;
private AttackBehavior attackBehavior;
public Robot(String name) {
this.name = name;
}
public void performAttack() {
attackBehavior.attack(name);
}
public void performMove() {
moveBehavior.move(name);
}
public void setMoveBehavior(MoveBehavior moveBehavior) {
this.moveBehavior = moveBehavior;
}
public void setAttackBehavior(AttackBehavior attackBehavior) {
this.attackBehavior = attackBehavior;
}
}
Class ARobot
public class ARobot extends Robot {
public ARobot(String name) {
super(name);
}
}
Class BRobot
public class BRobot extends Robot {
public BRobot(String name) {
super(name);
}
}
Main
public class Main {
public static void main(String[] args) {
ARobot aRobot = new ARobot("ARobot");
BRobot bRobot = new BRobot("BRobot");
aRobot.setAttackBehavior(new PunchBehavior());
aRobot.setMoveBehavior(new RunBehavior());
bRobot.setAttackBehavior(new MissileBehavior());
bRobot.setMoveBehavior(new FlyBehavior());
aRobot.performMove();
aRobot.performAttack();
bRobot.performMove();
bRobot.performAttack();
}
}

다음과 같이 디자인하게 되면 행동(기능)을 추가할 때, 기존 코드는 건드리지 않고 새로운 행동(기능)을 추가할 수 있게 된다.
| '인터페이스' 라는 것은 꼭 interface 구조를 지칭하는 것이 아닌 어떤 상위 형식(super type)에 맞춰 다형성을 활용하는 것이다. 객체의 변수 타입을 지정할 때 상위 형식을 사용한다면, 실제 그 객체에 변수를 대입할 때에는 어떤 하위객체든지 올 수 있다. |
Robot 클래스에서 어떤 행동을 할지 정의하지 않고, 객체를 생성할 때 참조되는 객체의 행동을 정의할 수 있도록 그 역할을 위임한다.

| is-a 관계보다 has-a 관계 상속보다는 구성을 활용한다. https://zangzangs.tistory.com/44 |
장점 :
- 컨텍스트 코드의 변경없이 새로운 전략을 추가할 수 있다. ( 컨텍스트에 대한 OCP 원칙을 만족)
단점 :
- 사용되는 전략이 적다면, 복잡성만 늘어나게 된다.
참고 :
[Design Pattern] 스트래티지 패턴(Strategy Pattern)
행위(Behavioral) 패턴행위를 클래스로 캡슐화해 동적으로 행위를 자유롭게 바꿀 수 있게 해주는 패턴같은 문제를 해결하는 여러 알고리즘이 클래스별로 캡슐화되어 있고 이들이 필요할 때 교체할
velog.io
[디자인패턴] 1. 스트래티지 패턴 개념과 예제 (strategy pattern)
Head First Design Patterns 책을 보고 정리한 내용입니다. 디자인 패턴을 처음 입문하시는 분들께 추천드리고픈 책입니다. 들어가면서... 디자인패턴을 왜 배워야 할까? 똑같은 객체지향 프로그래밍을
velog.io
https://gmlwjd9405.github.io/2018/07/06/strategy-pattern.html
[Design Pattern] 스트래티지 패턴이란 - Heee's Development Blog
Step by step goes a long way.
gmlwjd9405.github.io
| [Design Pattern] Builder Pattern (0) | 2023.03.25 |
|---|---|
| [Design Pattern] Decorator Pattern (0) | 2023.03.24 |
| [Design Pattern] Abstract Factory Pattern (0) | 2023.03.22 |
| [Design Pattern] Command Pattern (0) | 2023.03.21 |
| [Design Pattern] Factory Method Pattern (0) | 2023.03.19 |