새소식

개발/디자인패턴

[Design Pattern] Strategy Pattern

  • -

https://github.com/donghyeon-dev/StrategyPattern-with-Springboot

Strategy Pattern 이란?

behavior software design pattern that enables selecting an algorithm at runtime.
알고리즘을 런타임시 동적으로 선택할 수 있게 하는 행동디자인 패턴

  • 알고리즘을 정의하고 각각을 캡슐화하여 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.
  • 어떠한 객체의 행위를 캡슐화하여 행위을 행하는 전략에 따라 쉽게 행위를 바꿀수 있도록 도와준다.
  • 기능을 사용하는 부분구현하는 부분 을 명확히 분리하는것이 중요하다.

Strategy Pattern과 Solid 원칙

패턴을 소개할때 캡슐화라는 단어가 자주 사용되는걸 보면서 SOLID원칙과 연관이 되는 부분이 보였다.

  • 객체의 사용과 구현의 책임을 분리하는 SRP의 원칙
  • 기능확장이 유연하고 기능의 변경은 최소화(혹은 없거나) 하는 OCP 원칙
  • 부모(interface)의 메서드를 자식에서 구현 및 재정의가 이루어지는 LSP원칙

Use When

  • 행위기반적 클래스들간의 차이가 필요할때
  • 알고리즘의 다양한 버전, 변형이 요구될때
  • 런타임에 행위가 정의될 필요가 있을때
  • 조건문 사용이 복잡하고 유지하기 어려울때

구조

 


예시

네비게이션 앱을 예시로 선정했다.

초기버전은 차량 이용자만 사용하여 목적지까지 차량이동경로 만을 보여주면 되었지만 경로탐색의 다양성을 위해 대중교통을 이용하는사람, 도보로 이동하는사람 등 다양한 경로탐색(행위)을 위해 Strategy pattern을 사용한다.

+의존성 주입에 Strategy Pattern을 구현한다

  • Route라는 행위(경로검색)에 대한 Interface와 작성한다.
    enum으로 정의된 RouteName을 이용해서 각각의 전략을 구분한다.
public interface Route {
		
    String executeSearch();

    RouteName getRouteName();
}

public enum RouteName {
    WalkRoute,
    DriveRoute,
    PublicRoute
}​

 

  • 행위의 여러가지의 전략을 자식으로 구현해준다.
    @Component
    public class PublicRoute implements Route{
    
        @Override
        public String executeSearch() {
    		// 대중교통과 관련한 알고리즘 적용
            return "Publicroute";
        }
    
        @Override
        public RouteName getRouteName() {
            return RouteName.PublicRoute;
        }
    }
    
    @Component
    public class DriveRoute implements Route{
    
        @Override
        public String executeSearch() {
    		// 운전과 관련한 알고리즘 적용
            return "DriveRoute";
        }
    
        @Override
        public RouteName getRouteName() {
            return RouteName.DriveRoute;
        }
    }
    
    @Component
    public class WalkRoute implements Route{
    
        @Override
        public String executeSearch() {
    		// 보행과 관련한 알고리즘 적용
            return "WalkRoute";
        }
    
        @Override
        public RouteName getRouteName() {
            return RouteName.WalkRoute;
        }
    }​
  • RouteFactory를 Bean으로 만들고 모든 전략을 factory에 주입한다.
    @Component
    public class RouteFactory {
        // 모든 Route 전략을 주입
        private List<Route> routes;
    
        @Autowired
        public RouteFactory(List<Route> routeList){
            this.routes = routeList;
        };
    
        public Route findRoute(RouteName routeName){
            return routes.stream().filter(
                    route -> route.getRouteName().equals(routeName)
            ).findAny().get();
        }​


  • Controller와 Service 작성
    @RestController
    @RequiredArgsConstructor
    public class RouteController {
    
        private final RouteService routeService;
    
        @RequestMapping("/route")
        public String getRoute(@RequestBody RouteInput request) {
            return routeService.getRoute(request);
        }
    }​

     @Service
     @RequiredArgsConstructor
     public class RouteService {
    
         private final RouteFactory routeFactory;
    
         public String getRoute(RouteInput request){
             String routeStrategy = request.getStrategy();
             // 조건식을 덜 사용하기 위해 쓰는 패턴인데.. 예시니까..
             RouteName routeName = routeStrategy.equals("walk") ? RouteName.WalkRoute :
                     routeStrategy.equals("drive")? RouteName.WalkRoute :
                             RouteName.PublicRoute;
             Route route = routeFactory.findRoute(routeName);
             return route.executeSearch();
         }
     }


장점과 단점

장점

Context코드의 변경 없이 새로운 전략의 유연한 추가가 최대 장점이다. 요구사항이 변경되었거나 추가되었을때 기존 코드를 변경하지 않아도 된다는 점이 장점이며 객체지향 원칙에도 부합해 객체지향적 개발이 가능하게 도와준다.

단점

몇가지의 알고리즘만있고 거의 변경되지 않으면 분기가 더 편할지도 모른다. 또한 전략들로 애플리케이션 내 객체 수가 증가하게 된다.


Strategy Pattern in Java API

Stategy Pattern을 사용하여 구현한 라이브러리가 있다고 한다.

Strategy (recognizeable by behavioral methods in an abstract/interface type which invokes a method in an implementation of a different abstract/interface type which has been passed-in as method argument into the strategy implementation)

  • [java.util.Comparator#compare()](http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#compare-T-T-), executed by among others Collections#sort().
  • [javax.servlet.http.HttpServlet](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServlet.html), the service() and all doXXX() methods take HttpServletRequest and HttpServletResponse and the implementor has to process them (and not to get hold of them as instance variables!).
  • [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)

참고

https://ravthiru.medium.com/strategy-design-pattern-with-in-spring-boot-application-2ff5a7486cd8
https://velog.io/@hsw0194/스프링-부트-어플리케이션의-전략-패턴Strategy-Design-Pattern-with-in-Spring-Boot-application

https://velog.io/@ljinsk3/디자인-패턴-Strategy-Pattern

'개발 > 디자인패턴' 카테고리의 다른 글

[Design Pattern] 객체지향의 5대 원칙 Solid원칙  (0) 2021.07.24
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.