전략 패턴(Strategy Pattern) 어떻게 적용할 수 있을까?

DevSeoRex·2023년 7월 23일
9
post-thumbnail

🧐 디자인 패턴을 알아야 하는 이유는 뭘까?

여러번의 프로젝트를 진행해오면서 기능 구현을 위해 코드를 작성하는 일은 편안해졌지만 내가 작성한 코드에 대한 확신을 얻기는 아직 어려웠습니다.

그렇기에 좋은 코드에 대한 생각과 좋은 코드는 무엇일지, 좋은 설계를 하는 방법이 있을지에 대한 많은 생각을 해오게 되었습니다.

그런 생각을 하면서 이것저것 찾아보다가 디자인 패턴을 접하게 되었고, 하나 하나 찾아보면서 직접 코드로 작성해보고 체화하게 되었습니다.

  • 디자인 패턴이란?
    소프트웨어 공학의 소프트웨어 디자인에서 특정 문맥에서 공통적으로 발생할 수 있는 문제를 재사용 가능한 해결책을 제시안 템플릿의 모음이라고 볼 수 있습니다.

🤠 What is 전략 패턴?

전략 패턴(Strategy Pattern)이란, 캡슐화된 알고리즘(전략)을 교체하는 것만으로 런타임에 프로그램의 동작을 동적으로 변경할 수 있습니다.

전략 패턴을 활용하면, OCP(개방 - 폐쇄원칙)를 위반하지 않고 새로운 전략을 추가하는 것 만으로 코드의 수정없이 기능을 추가할 수 있다는 장점을 가지고 있습니다.

그렇다면 전략 패턴을 도입했을때 어떤 이익을 얻을 수 있는지 지금부터 코드로 살펴보겠습니다.

전략 패턴 도입 전 - OCP를 위반한 코드

A라는 사람이 슈퍼마켓을 개업했다고 가정해보겠습니다.

이 슈퍼마켓은 개업한지 얼마 되지 않아서, 손님도 없고 가맹점도 계약이 되지 않은 상태라 현금 결제만 된다고 가정하고 이 슈퍼마켓의 결제 시스템을 만들어보겠습니다.


결제할 금액을 매개변수로 받아 결제를 처리하는 performPayment 메서드를 가지고 있는 PaymentService 인터페이스를 만들어 주겠습니다.


PaymentService를 구현한 PaymentServiceImpl도 만들어 주겠습니다. 얼마가 결제되었는지 콘솔에 출력하는 간단한 역할을 하는 클래스입니다.

손님이 슈퍼마켓에서 2000원을 결제한다면 아래와 같은 코드로 그 동작을 구현할 수 있을것입니다.


코드도 예상대로 동작하고 아무런 문제도 일어나지 않습니다.
그렇다면 왜 전략패턴이 필요하다고 한걸까요? 이렇게 아무일도 일어나지 않고, 문제도 없습니다.

이 코드에서 간과한 부분은 현실속의 비즈니스는 요구사항이 변하고 언제든 새로운 요구를 받아들여야 한다는 것입니다.

결제 수단의 추가가 필요한 요구사항 발생

슈퍼마켓을 운영한지 일주일만에 카드 결제기를 놓게 되어서, 카드 결제도 가능해야 하는 상황이 생겼습니다.
손님이 3000원을 카드로 결제하려면 어떻게 코드를 수정해야 할까요?

performPayment 메서드는 얼마의 금액이 결제되는지만 알 수 있기 때문에 어떤 결제 방식을 택했는지 알 수 없습니다. 그렇다면 status라는 변수도 함께 제공받아서, 어떤 결제가 필요한지 알 수 있도록 코드를 수정해보겠습니다.



PaymentService와 PaymentServiceImpl의 코드를 변경하여 카드결제 기능을 추가했습니다.



status 값으로 결제 방식을 구분하고, 선택한 결제 방식으로 결제할 수 있도록 코드가 수정되었습니다.
여기서 조금만 더 생각해본다면, 카드 결제를 추가하면 앞으로 요구사항이 변경되는 일은 없을까요?

애플 페이, 네이버 페이, 삼성 페이, 포인트 결제 등 다양한 결제 수단의 추가를 요구한다면 이런 방식으로는 기능 추가를 위한 기존 코드 수정이 불가피합니다.

즉 OCP(개방 - 폐쇄 원칙)를 위반할 수 밖에 없다는 것입니다.
그렇다면 어떻게 전략 패턴을 활용해서 이 문제를 해결할 수 있을까요?

전략 패턴 도입 후 - OCP를 위반하지 않은 코드

전략패턴의 기본 아이디어는 캡슐화된 알고리즘군을 만들고, 캡슐화된 알고리즘군을 교체해서 사용할 수 있도록하는 것입니다.

만약 결제 수단이 5개 이상이라면 if ~ else if문을 이용한 분기 처리가 필요했을 것이고, 기능을 추가할때 분기 처리는 늘어나게 되어 프로그램 복잡도가 증가하게됩니다.


먼저 PaymentService와 같은 역할을 하는 PaymentStrategy 인터페이스를 만들어주겠습니다.
이전 코드에서는 PaymentService를 구현한 클래스에서 어떤 결제 방식을 선택했는지 분기 처리를 통해 파악하도록 모든 책임을 지고 있었습니다.

전략 패턴에서는 PaymentStrategy 인터페이스를 구현한 다양한 결제 전략 클래스(구현체)를 실행 시점에 Payment 클래스에 지정해주게 되면, 각 구현체에 맞는 결제 전략으로 결제되도록 구현합니다.

어떤 결제 방식이 추가 된다고 해도, Payment 클래스에 변경을 가져오지 않고 결제 전략을 변경하는 것으로 기능을 추가할 수 있게되어 OCP를 위반하지 않게 됩니다.

결제 전략 클래스를 작성




카드결제와 현금결제 그리고 스마트 월렛 결제 총 3가지 캡슐화된 알고리즘을 가진 전략 클래스 3개를 작성해주었습니다.

애플 페이, 카카오 페이 등 다양한 결제 수단이 추가 되어야 한다는 요구사항이 발생해도 결제 전략 클래스를 추가하는 것만으로 기능을 추가할 수 있게 되었습니다.

Payment 클래스 작성


Payment 클래스는 PaymentStrategy를 객체 생성시에 초기화 하게 되고, 실행 시점에 결제 방식을 변경할 필요가 생기면 setter 메서드를 이용해 전략을 변경할 수 있습니다.

Payment 클래스에서 결제를 진행하지 않고, 결제가 이루어지는 부분을 PaymentStrategy에 위임하게 됨으로서 Payment 클래스는 어떤 방식으로 결제를 하게 되는지 알필요가 없어졌습니다.

전략이 실행시점에 잘 교체되는지 확인

슈퍼마켓에서 고객이 1000원은 현금으로, 2000원은 카드로, 3000원은 스마트 월렛 결제를 사용한다고 가정하고 코드를 작성해보겠습니다.



캡슐화된 결제 전략을 변경하는 것 만으로, 실행시점에 결제 방식을 자유롭게 변경할 수 있다는 것을 확인했습니다.

😲 다음으로..

디자인 패턴을 공부하는 것이 좋은 코드를 작성하고 현실의 문제를 해결하는 데 많은 도움이 될것이라는 판단이 들게 되었던 것 같습니다.

객체지향 언어인 Java를 공부하고 개발을 해오면서, 클래스간의 의존성과 객체 지향 설계 원칙에 대해 고민하고 코드를 작성해보지 못한 것 같아서 앞으로도 디자인 패턴을 공부하고 코드로 이해하는 시간을 가져야겠다는 생각이 들었습니다.

오늘도 읽어주셔서 감사합니다.

🙇

참고한 레퍼런스

  • 헤드 퍼스트 디자인 패턴 개정판 - 한빛 미디어

4개의 댓글

comment-user-thumbnail
2023년 7월 23일

좋은 글이네요. 공유해주셔서 감사합니다.

1개의 답글
comment-user-thumbnail
2023년 7월 23일

생각을 딥하게 만들어 주는 글이네요~ 좋은 글 항상 감사합니다~ ㅎㅎㅎ

1개의 답글