전략 패턴(Strategy Pattern)

seunghyun lee·2022년 7월 13일
0

Computer Science

목록 보기
3/19
post-thumbnail

전략이란?

특정한 목표를 수행하기 위한 행동 계획


전략 패턴이란?

디자인 패턴 중에 하나로 객체가 할 수 있는 행위들 각각을 전략으로 만들어 놓고 사용하며, 동적으로 전략 수정이 가능한 패턴이다.
디자인 패턴: (소프트웨어)디자인 + (공통적으로 마주치는 문제를 해결하는 방법의) 패턴


  • 예시를 보며 이해해보자.

  • 로보는 움직이는 기능과 청소 기능이 있는 가정용 로봇이다.

  • 로봇의 종류에는 빠르게 움직이며 설거지를 하는 것느리게 움직이며 바닥을 쓰는 것이 있다.

기존의 방식

  • 이 로보를 코드로 구현한다면 다음과 같이 Robot 추상 클래스를 만들어 그 안에 move()와 clean()이라는 추상 메서드를 만들고, 이를 각각 FastAndWashDishesRobot과 SlowAndSweepFloorRobot 클래스가 상속 받게 만들 수 있다.

    추상클래스: 클래스에 필요한 메서드을 구현하지 않고 추상 메서드로 만들어 놓은 것.
    추상클래스를 사용하기 위해서는 추상클래스를 상속받아 추상 메서드를 오버라이딩을 통해 재정의 해주어야 한다.
    오버라이딩: 상속에서 메서드의 기능을 재정의하는 것이다.
    오버로딩: 파라미터가 다르다면, 같은 이름을 사용하는 것이 허용된다.

public abstract class Robot{
	public abstract void move();
    public abstract void clean();
}

class FastAndWashDishesRobot extends Robot {
	public void move() {
    	System.out.println("빨라빨라. 나는야 날쌘 로보. ")
    }
    public void clean() {
    	System.out.println("뽀득뽀득 설거지 중");
    }
}

class SlowAndSweepFloorRobot extends Robot {
	public void move() {
    	System.out.println("천천히 천천히. 나는야 느긋한 로보 ")
    }
    public void clean() {
    	System.out.println("쓰윽쓰윽 바닥 쓰는 중");
    }
}
  • 하지만 위와 같은 코드는 문제를 야기한다.
  • 아래와 같이 로보에 말하기 기능이 추가됐다고 가정하자.

문제 1. 새로운 기능의 추가가 어렵다.

  • 로보에 말하기 기능을 추가하기 위해서는 Robot 클래스에 talk()메서드를 추가 해야한다. 또한talk() 메서드를 추가할 경우 Robot을 상속받은 모든 클래스를 고쳐야하는 번거로움이 생기게 된다.
public abstract class Robot{
	public abstract void move();
    public abstract void clean();
	public abstract void talk(); 	//새로운 메서드 등장!
}

class FastAndWashDishesRobot extends Robot {
	public void move() {
    	System.out.println("빨라빨라. 나는야 날쌘 로보. ")
    }
    public void clean() {
    	System.out.println("뽀득뽀득 설거지 중");
    }
    public void talk() {System.out.println("말해봐요 말말 ")} 	//클래스 안 코드를 수정해야 한다. 
}

class SlowAndSweepFloorRobot extends Robot {
	public void move() {
    	System.out.println("천천히 천천히. 나는야 느긋한 로보 ")
    }
    public void clean() {
    	System.out.println("쓰윽쓰윽 바닥 쓰는 중");
    }
    public void talk() {System.out.println("나는야 말하는 로봇")} 	//클래스 안 코드를 수정해야 한다. 
}

문제 2. 메서드 수정이 어렵다.

  • 만약 빠르게 동작하는 로봇이 여러개 존재하고 이 동작을 모두 느린 동작으로 바꾼다고 가정하면, 모든 로보들의 클래스들 들추어 하나하나 메서드를 수정해야 한다. 이는 OCP 원칙에 위배 된다.

    OCP 원칙: 기능은 추가하되, 기존의 코드는 수정하지 않아야 한다


전략 패턴

  • 아래는 전략 패턴을 적용하여 로봇을 만든 예이다.
public interface MoveStrategy{ // 전략에 따른 인터페이스를 만듬
	void move();
}

class FastMove implements MoveStrategy {	// 전략을 implements함
	public void move() {
    	System.out.println("나는야 빠른 로봇");
    } 
}
class SlowMove implements MoveStrategy {
	public void move() {
    	System.out.println("느긋한 내가 좋다네~");
    }
}
  • 위와 같이 MoveStrategy interface를 만들어 fastMove 클래스와 slowMove 클래스가 implements하게 하였다.
  • 만약 talk라는 기능이 추가 된다면 interface TalkStrategy를 만들어 이를 implements한 클래스를 만들면 된다.
  • 또한 메서드가 바뀌게 되어도 하나의 클래스의 목표 부분만 수정하는 것이 가능하다.
  • 그리고 아래와 같이 같은 전략끼리는 갈아끼우는 것이 가능하다.

    interface vs abstract class
    부모가 여럿인 클래스를 다중상속이라고 하는데, 자바에서는 이를 금지한다.
    다만, interface를 implements 하면, 다중상속처럼 사용이 가능하다.
    interface는 여러개를 implements하는 것이 가능하다.

public interface MoveStrategy{ // 전략에 따른 인터페이스를 만듬
	void move();
}

class FastMove implements MoveStrategy {	// 전략을 implements함
	public void move() {
    	System.out.println("나는야 빠른 로봇");
    } 
}
class SlowMove implements MoveStrategy {
	public void move() {
    	System.out.println("느긋한 내가 좋다네~");
    }
}

abstract class Robot{
	private MoveStrategy movestrategy;	//전략
    
   public Robot(MoveStrategy movestrategy) {	
   		this.movestrategy = movestrategy;	//전략
   }
   public setMoveStrategy(MoveStrategy movestrategy){ // setter정의
   		this.movestrategy = movestrategy;
   }
}

// main 클래스
public class Main{
	public static void main(String[] args) {
      	Robot robo = new Robot(new FastMove()) // MoveStrategy로 업캐스팅된다. 
		robo.move(); // "나는야 빠른 로봇"
        robo.setMoveStrategy(new SlowMove());	
        robo.move(); // "느긋한 내가 좋다네~"
    }
}

장점 & 단점

  • 장점
    • 확장에 유리하다. (OCP)
    • 동일 전략의 알고리즘을 정의하고 각 알고리즘을 캡슐화하여 이들을 상호교환 가능하게 만든다.(ex. FastMove , SlowMove)
  • 단점
    + 복잡한 구조로 인해 비효율성을 초래할 수 있다.

0개의 댓글