본문 바로가기

개발공부/디자인패턴

[디자인패턴] 전략 패턴(Strategy Pattern)

💡 코드가 보이지 않으시다면 드래그 혹은 오른쪽 아래 🌜 아이콘을 눌러 테마 색을 변경해주세요.

 

 

안녕하세요!

키크니 개발자 입니다. 🦒

 

전략 패턴이란?

- 옵션들마다의 행동들을 모듈화해서 독립적이고 상호 교체 가능하게 만드는 것입니다.

- 객체들이 할 수 있는 동작을 각각의 전략으로 만들어 놓고 동적으로 동작을 변경해야 한다면 전략만 변경하여 동작이 바뀌도록 하는 패턴입니다.

- 일반적으로 if else로 구성된 코드 블록이 비슷한 기능 혹은 비슷한 알고리즘을 수행하는 경우에 전략 패턴을 적용함으로써 코드를 확장시킬 수 있습니다.

전략 패턴의 장점은?

- Strategy는 파싱 클래싱의 좋은 대안입니다. 클래스를 상속하고 메소드를 오버라이딩 하는 대신 단순한 인터페이스를 구현만 하면 됩니다.

-  Strategy 객체는 Context 클래스를 필요로 하지 않으며 알고리즘 특정 데이터에 집중할 수 있습니다.

- 시스템에 새로운 Strategy를 추가하기 쉽습니다. 

전략 패턴의 단점은?

- 통신 오버헤드가 클 수 있습니다. 즉, Strategy 객체의 전달된 인자의 일부가 사용되지 않을 수 있습니다.

예시

'얄팍한 코딩사전 : 객체지향 디자인패턴 1' 을 참고했습니다. 

 

상황

위와 같이 탭으로 구별되는 검색기능이 있다고 가정합니다.

분홍색으로 표시 된 버튼들 중 하나를 눌러서 모드를 설정하고,

선택 된 모드에 따라서 검색 버튼을 눌렀을 때 실행되는 검색의 방식이 결정되도록 하는 상황입니다.

즉 프로그램 실행 중 모드가 바뀔 때마다 검색이 이뤄지는 방식으로 전략이 수정된다고 볼 수 있습니다.

 

Before

 

전략 패턴을 활용하지 않는 코드 입니다.

public class MyProgram {

    private SearchButton searchButton = new SearchButton(this);

    public Mode mode = Mode.ALL; // (1)
    
    public void setModeAll() { mode = Mode.ALL; }
    public void setModeImage() { mode = Mode.IMAGE; }
    public void setModeNews() { mode = Mode.NEWS; }
    public void setModeMap() { mode = Mode.MAP; }

}

(1) 우선 현재 어떤 모드가 선택되어있는지 변수를 하나 만들어서 값을 넣어둡니다.

- 버튼들이 각각 메소드들(setModeAll(), setModeImage(), setModeNews(), setModeMap())을 실행한다고 가정합니다.

public enum Mode {
    ALL, IMAGE, NEWS, MAP
}
public class SearchButton {

    MyProgram myProgram;
    
    public SearchButton(MyProgram myProgram) {
        myProgram = myProgram;
    }

    public void onClick() { // (1)
        if (myProgram.mode == Mode.ALL) {
            System.out.println("SEARCH ALL");
            // 전체 검색하는 코드
            // ...
        } else if (myProgram.mode == Mode.IMAGE) {
            System.out.println("SEARCH IMAGE");
            // 이미지 검색하는 코드
            // ...
        } else if (myProgram.mode == Mode.NEWS) {
            System.out.println("SEARCH NEWS");
            // 뉴스 검색하는 코드
            // ...
        } else if (myProgram.mode == Mode.MAP) {
            System.out.println("SEARCH MAP");
            // 지도 검색하는 코드
            // ...
        }
    }
}

(1) searchButtononClick()이 실행되면 if문으로 그에 해당하는 동작이 행해집니다.

- 각각의 수정사항이 생기거나 기능이 추가되면 searchButtononClick 메소드를 그때그때 다시 수정해줘야합니다.

이렇게 구현을 하게 된다면 소프트웨어가 커지고 복잡해질수록 코드를 분석하고 관리하기 어려워집니다.

 

전략패턴은 모드마다의 동작 하나하나를 모듈로 따로 분리해서, 

이 버튼들을 누를때마다 검색버튼을 누를때 실행될 검색 모듈을 갈아끼워주는 방식으로 코드를 구현합니다. 

 

After

public class Main {
    public static void main(String[] args) {
        MyProgram myProgram = new MyProgram();
        myProgram.testProgram();
    }
}
public class SearchButton {
    
    MyProgram myProgram;
    
    public SearchButton(MyProgram myProgram) {
        myProgram = myProgram;
    }

    private SearchStrategy searchStrategy = new SearchStrategyAll(); // 1
    
    public void setSearchStrategy(SearchStrategy searchStrategy) { // 2
        searchStrategy = searchStrategy;
    }

    public void onClick() {
        searchStrategy.search();
    }
}

- 기존 onClick() 메소드에 if else문으로 탭 버튼에 맞춰 기능을 실행했지만, 전략 패턴을 사용한 후에는 SearchStrategy interface를 implements한 class의 search()로 기능을 실행합니다.

- 1 ) searchStrategy는 처음에 SearchStrategyAll 구현체로 초기화 되어있지만, 2)에 있는 setter를 통해서 SearchStrategy 인터페이스를 입은 다른 구현클래스(검색 전략)로 갈아끼울 수 있습니다.

public interface SearchStrategy {
    public void search();
}

class SearchStrategyAll implements SearchStrategy {
    @Override
    public void search() {
        System.out.println("SEARCH ALL");
        // 전체 검색하는 코드
    }
}

class SearchStrategyImage implements SearchStrategy {
    @Override
    public void search() {
        System.out.println("SEARCH IAMGE");
        // 이미지 검색하는 코드
    }
}

class SearchStrategyNews implements SearchStrategy {
    @Override
    public void search() {
        System.out.println("SEARCH NEWS");
        // 뉴스 검색하는 코드
    }
}

class SearchStrategyMap implements SearchStrategy {
    @Override
    public void search() {
        System.out.println("SEARCH MAP");
        // 지도 검색하는 코드
    }
}

- 각각 SearchStrategy를 implements 한 class는 onClick() 안에 있는 searchStrategy.search()를 실행시킬 수 있습니다.

- 수정사항이 있으면 해당 클래스를 찾아 내용을 수정하면 되고,

새 검색 방식이 추가가 되면 SearchStrategy를 implements한 새 클래스를 만들어서 연결해주면됩니다.

public class MyProgram {

    private SearchButton searchButton = new SearchButton(this);

    public Mode mode = Mode.ALL;
    
    public void setModeAll() {
        searchButton.setSearchStrategy(new SearchStrategyAll());
    }
    public void setModeImage() {
        searchButton.setSearchStrategy(new SearchStrategyImage());
    }
    public void setModeNews() {
        searchButton.setSearchStrategy(new SearchStrategyNews());
    }
    public void setModeMap() {
        searchButton.setSearchStrategy(new SearchStrategyMap());
    }

    public void testProgram() {
        searchButton.onClick(); // "SEARCH ALL" 출력
        setModeImage();         // 이미지검색 모드로 변경
        searchButton.onClick(); // "SEARCH IMAGE" 출력   
        setModeNews();          // 뉴스검색 모드로 변경
        searchButton.onClick(); // "SEARCH NEWS" 출력
        setModeMap();           // 지도검색 모드로 변경
        searchButton.onClick(); // "SEARCH MAP" 출력
    }
}

 

위의 예시를 본 후 아래의 예시를 보니 전략 패턴에 대해 더 잘 이해가 되었습니다. 😉

 

💡 전략 패턴 다른 예시

 

⭐️  참고한 곳  


얄팍한 코딩사전 : 객체지향 디자인패턴 1

https://www.youtube.com/watch?v=lJES5TQTTWE&t=1s

https://brownbears.tistory.com/574

https://kscory.com/dev/design-pattern/strategy

https://steady-coding.tistory.com/381

 

 

배워야 할 것이 더 많은 주니어 개발자입니다. 🐣
내용 전달보다는 정리를 목적으로 포스팅을 하고 있습니다.
잘못 된 내용이나 부족한 부분은 댓글로 주시면 감사드리겠습니다. 
반응형