GoF 디자인패턴(design pattern) 분류중 하나인 스트래티지(strategy)패턴을 살펴보던 중 **Java 8**의 **lambda**를 이용해서 더 쉽고 편하게 구현할 수 있을거라는 생각이 들었다. 기존의 **Strategy**패턴은 동작을 정의하는 인터페이스를 만들어서 이를 구현하는 실제 클래스를 만들고 캡슐화해서 변화에 유연하게 적용되어질 수 있도록 하는 것이다. 예제 코드를 작성해보면 다음과 같다.
## Strategy Pattern example
```java:line-numbers
public interface MoveStrategy {
void move();
}
public class WalkingStrategy implements MoveStrategy {
@Override
public void move() {
System.out.println("걸어서 이동");
}
}
public class FlyingStrategy implements MoveStrategy {
@Override
public void move() {
System.out.println("날아서 이동");
}
}
```
> 동작을 캡슐화하기 위해 `move()`라는 이름의 메소드를 갖는 인터페이스를 만들었다. 보다시피 **함수형 인터페이스**의 조건을 이미 만족하고 있기도 하다. 그리고 각각 날아다니는 포케몬과 걸어다니는 포케몬의 이동을 클래스로 구현한 `FlyingStrategy`와 `WalkingStrategy`를 확인할 수 있다.
```java:line-numbers
public abstract class Pokemon {
private int power;
private MoveStrategy moveStrategy;
public Pokemon(int power) {
this.power = power;
}
public void setMoveStrategy(MoveStrategy moveStrategy) {
this.moveStrategy = moveStrategy;
}
public void doMove() {
this.moveStrategy.move();
}
}
```
> 포케몬의 추상클래스이다. `MoveStrategy`를 멤버로 가지고 있고, 값을 설정하기 위해 `setMoveStrategy( ... )`를 만들어 두었다.
```java:line-numbers
public class Pikachu extends Pokemon {
public Pikachu(int power) {
super(power);
}
}
public class Pigeon extends Pokemon {
public Pigeon(int power) {
super(power);
}
}
```
> 추상클래스 `Pokemon`을 상속받는 `Pikachu`와 `Pigeon`클래스이다. **피카츄**는 걸어서 이동하고 **피죤**은 날아서 이동한다.
```java:line-numbers
public class GoPokemon {
public static void main(String[] args) {
Pokemon pikachu = new Pikachu(100);
Pokemon pigeon = new Pigeon(90);
pikachu.setMoveStrategy(new WalkingStrategy());
pigeon.setMoveStrategy(new FlyingStrategy());
System.out.print("피카추는 : ");
pikachu.doMove();
System.out.print("피죤은 : ");
pigeon.doMove();
}
}
```
```
피카추는 : 걸어서 이동
피죤은 : 날아서 이동
```
> 각 이동전략에 해당하는 클래스 구현체를 선택함으로써 새로운 포케몬이 추가되거나 이동방식이 변경되어도 쉽게 변화에 대응할 수 있다. 만약 수영을 해서 이동하는 포케몬이 추가 된다면 `MoveStrategy`를 구현하는 `SwimmingStrategy`를 만들어서 사용하면 되는것이다. 또는 피죤이 퇴화해서 걸어다니게 된다면 `WalkingStrategy`를 사용하도록 변경하는 것 또한 어렵지 않다.
# Using Lambda Expressions in Java 8
앞서 예제를 통해 본 스트래티지(strategy) 전략패턴을 살펴보면 모든 포케몬은 동일하게 이동(move)하지만 각각 그 방식이 다를 수 있다는 점을 고려해서 알맞은 이동전략을 구현하는 클래스를 전달하고 있다. 결국 동작을 캡슐화하고 구현체를 만들어서 사용하는 것인데, **Lambda**를 이용하면 동작 자체를 파라미터로 전달할 수 있게된다.
```java:line-numbers
public class GoPokemon {
public static void main(String[] args) {
Pokemon pikachu = new Pikachu(100);
Pokemon pigeon = new Pigeon(90);
// pikachu.setMoveStrategy(new WalkingStrategy());
// pigeon.setMoveStrategy(new FlyingStrategy());
pikachu.setMoveStrategy(() -> System.out.println("걸어서 이동 !"));
pigeon.setMoveStrategy(() -> System.out.println("날아서 이동 !"));
System.out.print("피카추는 : ");
pikachu.doMove();
System.out.print("피죤은 : ");
pigeon.doMove();
}
}
```
```
피카추는 : 걸어서 이동 !
피죤은 : 날아서 이동 !
```
> 이렇게 **Lambda**를 이용하면 별도의 클래스를 구현하지 않고도 각 포케몬에 대한 이동전략을 실행시점으로 미뤄서 유연하게 선택하도록 할 수 있다.
스트래티지(strategy) 디자인패턴을 보면서 충분히 **Lambda**표현식으로 처리할 수 있겠다고 생각을 하고 접근해보았다. 구글에 검색해보니 관련된 내용이 이미 많이 있었고 그 중 [Strategy Pattern using Lambda Expressions in Java 8](https://dzone.com/articles/strategy-pattern-using-lambda)를 참고하였다.