본문 바로가기

IT/디자인 패턴(Design Pattern)

[디자인 패턴] 전략 패턴(Strategy Pattern)

1) 개요

로직을 캡슐화하여 교환하며 상황에 맞는 로직을 사용하는 디자인 패턴입니다.


- 장점

1. 시스템의 구조 및 Context Class를 변경하지 않고 요청에 맞는 로직을 추가 및 수정할 수 있습니다.

2. 같은 인터페이스 양식을 가진 알고리즘을 별도로 캡슐화하여 코드의 가독성이 높아지며, 생산성이 높아집니다.

3. 요청에 맞는 로직을 실시간으로 변경할 수 있습니다.


- 단점

1. 상황에 맞는 적절한 로직을 모두 알고있어야 합니다.

2. 관리해야하는 클리스의 수가 늘어납니다.


- 패턴 비교

 상태 패턴(State Pattern)

 공통점

차이점 

 인터페이스를 사용하여 Concrete Class를 캡슐화합니다.

그에 따라, Concrete와 관계없이 인터페이스를 통하여 기능을 수행합니다.

 상태 패턴은 자신의 상태를 스스로 변환할 수 있습니다.

(전략 패턴은 외부에서 데이터를 입력 받아야 가능합니다.)


 방문자 패턴(Visitor Pattern)

 공통점

 차이점

 로직(알고리즘)을 캡슐화하여 사용자의 요청에 맞는 기능을 수행합니다.

 방문자 패턴은 다:다의 관계입니다. 저번 글에서 설명한 대로 비슷한 종류의 객체들을 가진 그룹에서 작업을 수행할 때 주로 사용하는 패턴이라는 점에서 알 수 있습니다. 

(전략 패턴은 1:다의 관계입니다. 하나의 객체(1)에 상황에 맞는 알고리즘(다)을 수행합니다.)



- 패턴 비교 결론

- Strategy Pattern : 로직을 소유한 객체를 실행 시 상황에 맞는 선택을 할 수 있음(내부의 상태가 아닌 외부에 의해 상황이 바뀔 경우)

- State Pattern : 상태변화가 복잡하고 다양할 경우 사용(상태에 따른 조건문이 많을 경우)

- Visitor Pattern : 대응해야하는 객체의 수가 많고 그에 따른 행동이 각각 다를 경우 사용



2) UML



3) 예제

1
2
3
4
public interface KickBehavior {
    public void kick();
}
 
cs


1
2
3
4
public interface JumpBehavior {
    public void jump();
}
 
cs


1
2
3
4
5
6
7
public class LightningKick implements KickBehavior{
    @Override
    public void kick() {
        System.out.println("Lightning Kick");
    }
}
 
cs


1
2
3
4
5
6
7
public class TornadoKick implements KickBehavior{
    @Override
    public void kick() {
        System.out.println("Tornado Kick");
    }
}
 
cs


1
2
3
4
5
6
7
public class LongJump implements JumpBehavior{
    @Override
    public void jump() {
        System.out.println("Long Jump");
    }
}
 
cs

1
2
3
4
5
6
7
public class ShortJump implements JumpBehavior{
    @Override
    public void jump() {
        System.out.println("Short Jump");
    }
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public abstract class Fighter {
    KickBehavior kickBehavior;
    JumpBehavior jumpBehavior;
    
    public Fighter(KickBehavior kickBehavior, JumpBehavior jumpBehavior) {
        this.kickBehavior = kickBehavior;
        this.jumpBehavior = jumpBehavior;
    }
    
    public void punch() {
        System.out.println("Default Punch");
    }
    
    public void kick() {
        kickBehavior.kick();
    }
    
    public void jump() {
        jumpBehavior.jump();
    }
    
    public void roll() {
        System.out.println("Default Roll");
    }
    
    public void setKickBehavior(KickBehavior kickBehavior) {
        this.kickBehavior = kickBehavior;
    }
    
    public void setJumpBeahvior(JumpBehavior jumpBehavior) {
        this.jumpBehavior = jumpBehavior;
    }
    
    public abstract void display();
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Ryu extends Fighter{
 
    public Ryu(KickBehavior kickBehavior, JumpBehavior jumpBehavior) {
        super(kickBehavior, jumpBehavior);
    }
 
    @Override
    public void display() {
        System.out.println("Ryu");
    }
 
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Ken extends Fighter{
 
    public Ken(KickBehavior kickBehavior, JumpBehavior jumpBehavior) {
        super(kickBehavior, jumpBehavior);
    }
 
    @Override
    public void display() {
        System.out.println("Ken");
    }
 
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ChunLi extends Fighter{
 
    public ChunLi(KickBehavior kickBehavior, JumpBehavior jumpBehavior) {
        super(kickBehavior, jumpBehavior);
    }
 
    @Override
    public void display() {
        System.out.println("ChunLi");
    }
 
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class StreetFighter {
    public static void main(String[] args) {
        JumpBehavior shortJump = new ShortJump();
        JumpBehavior LongJump = new LongJump();
        KickBehavior tornadoKick = new TornadoKick();
        
        Fighter ken = new Ken(tornadoKick, shortJump);
        ken.display();
        
        ken.punch();
        ken.kick();
        ken.jump();
        
        ken.setJumpBeahvior(LongJump);
        ken.jump();
    }
}
 
cs