실행 중에 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴으로, 특정한 계열의 알고리즘들을 정의하고, 각 알고리즘을 캡슐화하며, 이 알고리즘들을 해당 계열 안에서 상호 교체가 가능하게 만든다.
1) 객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성
2) 유사한 행위들을 캡슐화 하는 인터페이스를 정의
3) 객체의 행위를 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함
Strategy
(인터페이스 or 추상 클래스)ConcreteStrategy
(구현 클래스)Context
fly
, quack
, swim
, display
quack
, swim
, display
swim
, display
⭐디자인원칙 1. 바뀌는 부분을 바뀌지 않는 부분으로부터 분리시킨다.
swim
과 display
는 일정하고, fly
와 quack
이 바뀐다.
각각의 행동을 구현한 클래스를 Duck 클래스로부터 독립적으로 만들어서 구현해보자.
fly행동을 구현한 인터페이스 FlyBehavior
, quack행동을 구현한 인터페이스 QuackBehavior
Duck과 Behavior의 완벽한 분리를 이루어내자.
다른 Behavior 혹은 새로운 Duck 클래스 생성 가능 "확장이 쉬움"
⭐디자인원칙 2. 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.
각 행동의 큰 틀은 인터페이스 FlyBehavior
, QuackBehavior
로 표현하고, 구체적인 설명은 각 인터페이스를 상속받아 구현한다.
⭐디자인원칙 3. 상속보다는 구성을 활용한다.
오리클래스들은 특정 행동을 상속받는 것이 아닌, 특정 행동객체(FlyBehavior
와 QuackBehavior
)로 구성됨으로써 행동이 부여된다.
Strategy (Interface, 오리마다 바뀌는 행동 골라서 만듦)
public interface FlyBehavior{
void fly();
}
public interface QuackBehavior{
void quack();
}
ConcreteStrategy (Strategy에서 명시한 각각의 행동을 구현한 클래스)
public class Quack implements QuackBehavior{
@Override
public void quack(){
System.out.println("quack");
}
}
public class MuteQuack implements QuackBehavior{
@Override
public void quack(){
}
}
public class Squeak implements QuackBehavior{
@Override
public void quack(){
System.out.println("squeak");
}
}
public class FlyNoWay implements FlyBehavior{
@Override
public void fly(){
}
}
public class FlyWithWings implements FlyBehavior{
@Override
public void fly(){
System.out.println("fly with wings");
}
}
Context (Strategy 패턴과 setter메서드를 활용하여 오리의 행동 명시)
public class Duck{
private FlyBehavior flyBehavior;
private QuackBehavior quackBehavior;
public void swim(){
System.out.println("swim");
}
public void display(){
System.out.println("Duck");
}
public void performQuack(){ // Strategy 패턴 이용 (interface에서 호출)
if (quackBehavior != null){
quackBehavior.quack();
}
}
public void performFly(){ // Strategy 패턴 이용 (interface에서 호출)
if (flyBehavior != null){
flyBehavior.fly();
}
}
public void setQuackBehavior(QuackBehavior quackBehavior){ // QuackBehavior 지정 함수
this.quackBehavior = quackBehavior;
}
public void setFlyBehavior(FlyBehavior flyBehavior){ // FlyBehavior 지정 함수
this.flyBehavior = flyBehavior;
}
}
public class MallardDuck extends Duck{
public MallardDuck(){
setQuackBehavior(new Quack()); // QuackBehavior를 Quack으로 지정
setFlyBehavior(new FlyWithWings()); // FlyBehavior를 FlyWithWings로 지정
}
@Override
public void display(){
System.out.println("Mallard Duck");
}
}
public class RuberDuck extends Duck{
public RubberDuck(){
setQuackBehavior(new Squeak());
setFlyBehavior(new FlyNoWay());
}
@Override
public void display(){
System.out.println("Rubber Duck");
}
}
public class DecoyDuck extends Duck{
public DecoyDuck(){
setQuackBehavior(new MuteQuack());
setFlyBehavior(new FlyNoWay());
}
@Override
public void display(){
System.out.println("Decoy Duck");
}
}
Main
public class Main{
public static void main(Strings[] args){
Duck duck1 = new MallardDuck();
duck1.display();
duck1.performQuack();
duck1.performFly();
Duck duck2 = new RubberDuck();
duck2.display();
duck2.performQuack();
duck2.performFly();
Duck duck3 = new DecoyDuck();
duck3.display();
duck3.performQuack();
duck3.performFly();
}
}
// 결과
Mallard Duck
quack
fly with wings
Rubber Duck
squeak
Decoy Duck