전략 패턴은 무엇이고, 어떻게 활용할 수 있을까?

김재연·2023년 12월 24일
2

전략 패턴은 무엇이고, 어떻게 활용할 수 있을까?

전략 패턴이 뭐야?

다들 만연하게 전략 패턴의 이름에 대해서는 들어봤을 것입니다.

얼마전까지만 해도 Java 에 익숙하지 않던, 아니 더 나아가서 객체지향에 익숙하지 않던 저에게도 들어본 적은 있지만, 도대체 무엇인지 모르는 개념이었습니다.

이름에서부터 풍겨오는 느낌은 다양한 전략을 사용한다는 것? 이 정도로 느껴집니다.

과연 전략패턴은 무엇일까요?

전략 패턴은 알고리즘들의 패밀리를 정의하고, 각 패밀리를 별도의 클래스에 넣은 후 그들의 객체들을 상호교환할 수 있도록 하는 행동 디자인 패턴입니다.

더 쉽게 말하면, 별도의 클래스들에 알고리즘 전략들을 집어넣어놓고, 상황에 맞게 갈아끼운다는 것입니다.

근데.. 도대체 이게 왜 필요할까요?

네비게이터 앱

우리가 공을 들여서 네비게이터 앱을 개발했다고 가정해볼게요.

어렵게 어렵게, 자동차로 이동할 때 출발지부터 목적지까지의 최적의 경로를 추출해내고, 안내해주게끔 만들었어요.

사람들의 반응은 뜨거웠습니다.

하지만, 점점 사람들이 도보로 이동하는 최적의 경로도 원하기 시작했어요.

서비스가 흥하기 위해서는 당연히 사용자의 피드백에 따라야겠죠?

도보로 이동하는 최적의 경로도 만들어냈습니다.

하지만, 이어서 자전거 등등 계속해서 사용자들이 원하기 시작했어요.

서비스는 흥했지만, Main 클래스의 코드는 점점 스파게티 코드가 되어갔습니다.

한 줄을 고칠 때마다, 예기치 못한 오류가 수도 없이 발생했습니다.

코드를 유지보수 하는 것이 너무 힘들어진 것입니다.

이를 어떻게 해결할 수 있을까요?

해결법

간단합니다.

하나의 클래스에 알고리즘들을 모아놓지 않으면 됩니다.

즉, 자동차, 도보, 자전거 등등의 경로를 구하는 알고리즘을 다른 클래스로 분리하면 되는 것입니다.

그러고서 상황에 맞게 알고리즘들을 선택하면 됩니다.

구조


구조에 대한 설명을 간략하게 하면 알고리즘을 사용할 메서드를 정의해놓고, 알고리즘을 구현하는 구현체가 해당 메서드를 구현하면 되는 것입니다.

그러고서 Navigator (Context) 이를 사용하기만 하면되는 것이죠.

Navigator 는 알고리즘 내부 사정이 어떻게 되는지 신경쓰지 않아도 됩니다.

이를 통해 나온 결과를 가지고, 잘 활용하기만 하면 되는 것이죠!

이를 간단하게 구현해볼까요?

  • Strategy
public interface RouteStrategy {

	경로 buildRoute(위치 A, 위치 B);

}

public class RoadStrategy implements RouteStrategy {

	public 경로 buildRoute(위치 A, 위치 B) {
		... 구현부
	}

}

public class WakingStrategy implements RouteStrategy {

	public 경로 buildRoute(위치 A, 위치 B) {
		... 구현부
	}

}

public class BicycleStrategy implements RouteStrategy {

	public 경로 buildRoute(위치 A, 위치 B) {
		... 구현부
	}

}

위와 같은 형식으로 전략 부분을 설정하시면 되구요

  • Context
public class Navigator {

	private RouteStratgy routeStrategy;

	public Navigator(RouteStratgy routeStrategy) {
		this.routeStrategy = routeStrategy;
	}

	public 경로 buildRoute(위치 A, 위치 B) {
		// 전처리
		경로 route = routeStrategy.buildRoute(A, B);
		// 후처리
	}
}

public class Client {

	public static void main(String[] args) {
		Navigator 자동차경로네비게이터 = Navigator(new RoadStrategy());
		Navigator 도보경로네비게이터 = Navigator(new WakingStrategy());
		Navigator 자전거경로네비게이터 = Navigator(new BicycleStrategy());

		...이를 사용하는 로직들
	}

}

이런 식으로 사용하면 디자인 패턴을 실질적으로 활용할 수 있는 것입니다.

장점 및 단점

장점 및 단점으로 아래와 같은 점들이 있습니다.

  • 장점
  1.  런타임에 한 객체 내부에서 사용되는 알고리즘들을 교환할 수 있습니다.
  2.  알고리즘을 사용하는 코드에서 알고리즘의 구현 세부 정보들을 고립할 수 있습니다.
  3.  상속을 합성으로 대체할 수 있습니다.
  4.  개방/폐쇄 원칙. 콘텍스트를 변경하지 않고도 새로운 전략들을 도입할 수 있습니다.
  • 단점
  1.  알고리즘이 몇 개밖에 되지 않고 거의 변하지 않는다면, 패턴과 함께 사용되는 새로운 클래스들과 인터페이스들로 프로그램을 지나치게 복잡하게 만들 이유가 없습니다.
  2.  클라이언트들은 적절한 전략을 선택할 수 있도록 전략 간의 차이점들을 알고 있어야 합니다.
  3.  현대의 많은 프로그래밍 언어에는 익명 함수들의 집합 내에서 알고리즘의 다양한 버전들을 구현할 수 있는 함수형 지원이 있으며, 클래스들과 인터페이스들을 추가하여 코드의 부피를 늘리지 않으면서도 전략 객체를 사용했을 때와 똑같이 이러한 함수들을 사용할 수 있습니다.

아무래도 장점은 각 객체들에게 역할을 확실히 부여함에 따라서, 변경에 유연하다는 것인 것 같습니다.

단점으로는, 전략 패턴을 무분별하게 사용하다보면 클래스, 인터페이스로 인해서 프로그램이 커지며, 지나치게 복잡해 질 수 있다는 것입니다.

그리고, 이를 사용하는 개발자가 전략들의 차이점에 대해서 명확하게 알고 있어야 하죠!

그렇더라도, 잘 사용하면 정말 좋은 패턴인 것 같습니다!

이를 잘 활용해서 조금 더 객체지향적인 코드를 짜볼 수 있도록 노력해봅시다!

참고 자료

전략 패턴에 대한 글

profile
끊임없이 '성장'하는 개발자 김재연입니다.

2개의 댓글

comment-user-thumbnail
2023년 12월 24일

오호 이해가 아주 잘 되는군여~~!

1개의 답글