본문 바로가기

Backend/Java Design Pattern

[JAVA 디자인 패턴] 스트래티지 패턴 ( Strategy Pattern)

728x90

JAVA 디자인 패턴 스터디를 하면서 공부한 내용들을 정리 보려고 합니다. 

"JAVA 객체지향 디자인 패턴" 책을 참고하면서 작성했습니다.

 

디자인 패턴을 사용할때는 "왜? 쓰는가?, 쓰면 뭐가 좋은가? 안쓰면 무슨 문제가 있는가?"에 대해서 먼저 완벽히 학습을 한뒤에 구체적인 예제를 코딩해보면서 공부하는 것이 효율적인 것 같습니다. 이런 디자인 패턴이 실제 코딩을 할때 어떤 패턴을 사용할지 적용할 수 있기 때문입니다. 

 

그렇기 때문에 "왜 스트래티지 패턴을 사용하는가?" 에 대해 알아보고, 구체적인 코드를 통해 예시를 보겠습니다. 

 

1. 로봇 만들기

 

"로봇" 을 만들때 , 우리는 객체지향의 상속의 개념을 통해 

Robot class 에 구체적인 로봇인 TakewonV class, Atom class 이렇게 만들 수 있습니다.

 

로봇 설계 UML

2. 문제점

 

위와 같이 UML을 설계한다면 몇가지 문제점이 발생할 수 있습니다.

 

 1) 기존 로봇의 공격, 이동 방법을 수정할때? 

 2) 새로운 로봇을 만들어 공격, 이동 방법을 수정하고 싶다면?

 

만약 이런 상황이 생기면, 각각 TaekwonV 클래스와 Atom 클래스에 직접 메서드를 각각 수정하여야 할 것입니다. 

 

*문제 ? : "새로운 기능을 위해 기존 코드를 수정한다?" 

=> 객체지향 설계 원칙인 SOLID 중 OCP (개방-폐쇄 원칙) 을 위배하게 됩니다.

 

또한 Atmo 클래스의 move 메서드와 TaekwonV 클래스의 move 메서드가 동일한 기능을 실행하므로 기능이 중복되는 상황이 발생하기 됩니다. 이런 중복은 크리티컬한 문제를 야기하는 원인이 될 수 있습니다. 여기서는 2가지의 로봇의 종류가 있지만 종류가 많아지면,  중복코드를 일관성 있게 유지하는 것이 중요한 일입니다. 

 

3. 해결책

 

로봇 설계에서 문제점을 해결하려면 어떤 부분이 변화했는지를 알아봐야합니다.  어디가 변화되는지 찾고, 그것을 클래스로 캡슐화 시켜야합니다. 여기서 변화하는 부분은 move(), attack() 메서드 관련부분입니다. 이동방식, 공격방식은 계속 추가되고 변화 될 수 있으므로 이부분을 고쳐야합니다. 

 

이부분을 캡슐화하려면 외부에서 구체적인 이동방식, 공격방식을 담은 구체적인 클래스들을 이용하여 은닉하여합니다.

이를 위해 공격과 이동을 위한 인터페이스를 만들고, 이들을 실제 실현한 클래스를 만들어야 합니다. 

 

인터페이스를 구현한 방식을 보겠습니다.

Move() , Attack()을 전략패턴을 이용 인터페이스 만들기

 

Strategy Pattern을 이용해 개선된 설계 방식

Robot 클래스에서 기존의 방식과 다르게 구체적인 이동 방식, 공격 방식을 MovingStrategy, AttackStrategy 인터페이스에 의해 캡슐화 하였다. 

 

 1) 인터페이스의 변화에 대한 일종의 방화벽 역할을 수행해 Robot 클래스의 변경을 차단해준다!

 2) 새로운 기능의 추가가 기존의 코드에 영향을 미치지 않아, OCP를 만족한다!

 

직접 사용하는 방식은 Robot 클래스에 setMovingStrategy와 setAttackStrategy 메서드를 이용해 로봇의 이동 방식과 공격 방식이 필요할때 마다 사용하면 되겠습니다. 

 

 

1. Robot.java 

 

public abstract class Robot {
	public String name;
	public MovingStrategy movingStrategy;
	public AttackStrategy attackStrategy;
	
	public Robot(String name) {
		this.name = name;
	}
	public String getName() {
		return this.name; 
	}
	public void move() {
		movingStrategy.move();
	}
	public void attack() {
		attackStrategy.attack();
	}
	public void setMovingStrategy(MovingStrategy movingStrategy) {
		this.movingStrategy = movingStrategy;
	}
	public void setAttackStrategy(AttackStrategy attackStrategy) {
		this.attackStrategy = attackStrategy;
	}
}

 

2. TaekwonV.java

 

public class TaekwonV extends Robot{
	public TaekwonV(String name) {
		super(name);
	}
}

 

3. Atom.java

 

public class Atom extends Robot{
	public Atom(String name) {
		super(name);
	}
}

 

4. MovingStrategy.java - 각 로봇이 취할 수 있는 이동방법에 대한 인터페이스

 

interface MovingStrategy {
	public void move();
}

 * 각 이동 방법을 실제로 구현.

 

4-1) WalkingStrategy.java

 

public class WalkingStrategy implements MovingStrategy{
	@Override
	public void move() {
		System.out.println("walk");
	}
}

 

4-2) FlyingStrategy.java

 

public class FlyingStrategy implements MovingStrategy {
	@Override
	public void move() {
		System.out.println("fly");
	}
}

 

5. AttackStrategy.java - 각 로봇이 취할 수 있는 공격방법에 대한 인터페이스

 

interface AttackStrategy {
	public void attack();
}

 

 * 각 공격 방법을 실제로 구현.

5-1) MissileStrategy.java

 

public class MissileStrategy implements AttackStrategy {

	@Override
	public void attack() {
		System.out.println("missle");
	}

}

 

5-2) PunchStrategy.java

 

public class PunchStrategy implements AttackStrategy {

	@Override
	public void attack() {
		System.out.println("punch");
	}

}

 

6. Client.java - main 실행

 

public class Client {

	public static void main(String[] args) {

		Robot taekwonV = new TaekwonV("taekwonV");
		Robot atom = new Atom("Atom");
		
		taekwonV.setMovingStrategy(new WalkingStrategy());
		taekwonV.setAttackStrategy(new MissileStrategy());
		
		atom.setMovingStrategy(new FlyingStrategy());
		atom.setAttackStrategy(new PunchStrategy());
		
		System.out.println("my name is " + taekwonV.getName());
		taekwonV.move();
		taekwonV.attack();
		
		System.out.println("my name is "+ atom.getName());
		atom.move();
		atom.attack();
		
	}

}

 

참고자료 : Java 객체지향 디자인 패턴, 한빛미디어, 정인상 채흥석 저, 2014

728x90