개발자로 (글을 쓰고 있을 당시) 5년차에 접어들었는데, 딱히 패턴의 중요성을 인식하지 못하여 맨날 사용하는 패턴으로 개발을 하고 있었습니다. 하지만 한가지 패턴으로만 개발하는데 한계를 느끼게 되어 새로운 패턴들을 공부해보기로 하였습니다.
그래서 그 첫번째로 전략적 패턴(스트레티지 패턴)에 대해 알아보겠습니다.
스트래티지 패턴은 행위에 대한 알고리즘군을 만들고 각각의 캡슐화 하여 교환해서 사용할 수 있도록 만드는 패턴입니다. 즉, 전략적으로 쉽게 필요한 부분을 쉽게 변경하도록 하는 패턴입니다. (여기서 전략이란 어떤 목적을 달성하기 위해 일을 수행하는 방식, 비즈니스 규칙, 문제를 해결하는 알고리즘 등을 말합니다.)
이 패턴의 디자인원칙은
1. 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리시킨다.
2. 상속보다는 구성을 활용한다.
3. 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.
1번이 제일 중요한 디자인원칙이고 2번 3번은 구현 방법으로 생각하는게 좋을 것 같습니다.
그럼 예시를 들어보겠습니다.
토니가 아이언맨을 만들었습니다. Mark_1과 Mark_2를 말이죠. Mark_1과 Mark_2는 공격할 수 있고 움직일 수 있습니다.
public abstract class IronMan {
private String version;
public IronMan(String version ){
this.version = version;
}
public String getVersion(){
return version;
}
public abstract void attack();
public abstract void move();
}
public class Mark_1 extends IronMan {
Mark_1(){
super("Mark-1");
}
@Override
public void attack() {
System.out.println("Mark-1 attack");
}
@Override
public void move() {
System.out.println("Mark-1 move");
}
}
public class Mark_2 extends IronMan {
Mark_2(){
super("Mark-2");
}
@Override
public void attack() {
System.out.println("Mark-2 attack");
}
@Override
public void move() {
System.out.println("Mark-2 move");
}
}
public class Tony {
public static void main(String[] arg){
Mark_1 mk1 = new Mark_1("Mark_1");
mk1.attack();
mk1.move();
Mark_2 mk2 = new Mark_2("Mark_2");
mk2.attack();
mk2.move();
}
}
이렇게 할 경우 문제 점이 있습니다.
Mark_1의 경우에는 상관없지만 Mark_2의 경우 레이저도 쏘고 날수도 있기 때문입니다.
그런데 여기서 Mark_2의 move와 attack을 수정할 경우 OCP를 위반하게 됩니다. 그래서 위에서 설명했듯이 (전략적으로 쉽게 필요한 부분을 쉽게 변경하도록 하는 패턴) 변경해야하는 부분을 찾고 그 부분을 클래스로 캡슐화 하여 사용하도록 하겠습니다. 변경해야하는 부분은 Attack과 Move이고 이에 대한 interface를 만들고 필요에 따라 변경하여 사용하도록 디자인을 합니다
구현은 다음과 같습니다.
public interface Attack_strategy {
public void attack(String version);
}
class FireAttack implements Attack_strategy{
@Override
public void attack(String verion) {
System.out.println(verion+ " Fire Attack");
}
}
class LaserAttack implements Attack_strategy{
@Override
public void attack(String verion) {
System.out.println(verion+ " Laser Attack");
}
}
class MissileAttack implements Attack_strategy{
@Override
public void attack(String verion) {
System.out.println(verion+ " Missile Attack");
}
}
public interface Move_strategy {
public void move(String verion);
}
class Fly implements Move_strategy{
@Override
public void move(String verion) {
System.out.println(verion+" Fly Move");
}
}
class Walk implements Move_strategy{
@Override
public void move(String verion) {
System.out.println(verion+" Walk Move");
}
}
public class Mark_1 extends IronMan {
Mark_1() {
super("Mark_1");
}
}
public class Mark_2 extends IronMan {
Mark_2(){
super("Mark_2");
}
}
public abstract class IronMan {
private String version;
private Attack_strategy attack_strategy;
private Move_strategy move_strategy;
public IronMan(String version ){
this.version = version;
}
public String getVersion(){
return version;
}
public void setAttack_strategy(Attack_strategy attack_strategy){
this.attack_strategy = attack_strategy;
}
public void setMove_strategy(Move_strategy move_strategy){
this.move_strategy = move_strategy;
}
public void attack(){
attack_strategy.attack(version);
};
public void move(){
move_strategy.move(version);
};
}
public class Tony {
public static void main(String[] arg){
Mark_1 mk1 = new Mark_1();
mk1.setAttack_strategy(new FireAttack());
mk1.setMove_strategy(new Walk());
mk1.attack();
mk1.move();
Mark_2 mk2 = new Mark_2();
mk2.setAttack_strategy(new LaserAttack());
mk2.setMove_strategy(new Fly());
mk2.attack();
mk2.move();
}
}
결과
Mark_1 Fire Attack
Mark_1 Walk Move
Mark_2 Laser Attack
Mark_2 Fly Move
Mark_1 Missile Attack
이렇게 구현을 하면 IronMan class가 Attack과 Move를 이용하는 클라이언트가 되고 구체적인 Attack과 Move는 Attack_strategy와 Move_Strategy에 의해 캡슐화 됩니다. 그리고 새로운 기능을 추가할 경우 각 strategy를 implements하여 기능을 만들어 사용하면 됩니다.
이런 패턴을 통하여 새로운 기능의 추가(새로운 이동, 공격 기능)가 기존의 코드에 영향을 미치지 못하게 하므로 OCP를 만족 하는 설계가 된다. 그리고 외부에서 새로운 이동과 공격방식을 임의대로 바꾸도록 해주는 setter 메서드로 setAttack_strategy, setMove_strateg를추가합니다.
이 패턴을 공부하면서 느꼈던 부분은 기준 골격을 만들고 각 부분에 필요에 따른 기능을 부착하는 느낌을 강하게 받는 패턴이었습니다.
참고:
https://gmlwjd9405.github.io/2018/07/06/strategy-pattern.html
'2023년 이전 > 디자인 패턴' 카테고리의 다른 글
디자인 패턴 - 컴퍼지트 패턴 (Composite Pattern) (0) | 2019.11.19 |
---|---|
디자인 패턴 - 데코레이터 패턴(Decorator Pattern) (0) | 2019.11.18 |
디자인 패터 - 옵저버 패턴(Observer Pattern) (0) | 2019.11.18 |
디자인 패턴 - 커맨드 패턴(Command Pattern) (0) | 2019.11.15 |
디자인 패턴 - 싱글턴 패턴(Singleton Pattern) (0) | 2019.11.14 |