본문 바로가기

Domain/디자인패턴

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

전략 패턴(Strategy Pattern)

각 객체들이 하게 될 행위에 대해 전략 클래스를 생성하고, 유사한 행위를 캡슐화하는 인터페이스를 정의하여, 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고, 전략(객체)을 바꿔주기만 함으로써 유연하게 확장하는 방법을 의미한다.

각 행위를 각각의 객체로 만들고, 행위의 변경이 필요한 경우 전략을 바꾸는 방식

 

UML

 

  • Strategy: 외부에서 전략을 교체하는 인터페이스. 추상 메서드를 활용한다.
  • ConcreteStrategyA/ConcreteStrategyB : 전략 객체
  • Context: Strategy를 실제 주입받아 사용하는 객체전략 패턴(Strategy Pattern)

 

실 사용 예시

위의 구글 검색의 경우 전체/이미지/뉴스/동영상/지도 탭을 누를 때 마다 각각 정보를 보여주는 전략이 다르다. 이 5개의 탭을 교체하는게 Strategy가 되고 각각이 ConcreteStrategyA/B/C/D/E가 될 수 있다.

 

 

 

좋지 않은 코드 예시

class MainActivity : AppCompatActivity() {
    private var mode = Mode.ALL //MODE {ALL,IMAGE,NEWS,MAP}

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        serach_btn.setOnClickListener { 
            when(mode){
            	Mode.ALL -> {
                	//전체 검색하는 코드
                }
                Mode.IMAGE -> {
                	//이미지 검색하는 코드
                }
                Mode.NEWS -> {
                	//뉴스 검색하는 코드
                }
                Mode.MAP -> {
                	//지도 검색하는 코드
                }
            }
        }
    }
}

위의 경우 현재 어떤 탭이 클릭되었는지에 따라 when(switch)문으로 분기하여 서로 다른 알고리즘을 구현한다. 이 경우 전략이 늘어나거나 이와 비슷한 검색창이 다른 곳에서도 활용될 경우에 유연하지 못하다.

 

 

개선된 코드

공통 행위에 대한 인터페이스 지정 및 전략 별 클래스 생성

interface SearchStrategy{
    fun search()
}

class AllSearchStrategy : SearchStrategy{
    override fun search(){
    	//전체 검색 코드
    }
}
class ImageSearchStrategy : SearchStrategy{
    override fun search(){
    	//전체 검색 코드
    }
}
class NewsSearchStrategy : SearchStrategy{
    override fun search(){
    	//전체 검색 코드
    }
}
class MapSearchStrategy : SearchStrategy{
    override fun search(){
    	//전체 검색 코드
    }
}

 

실제 사용

class MainActivity : AppCompatActivity() {
    private var searchStrategy : SearchStrategy = AllSearchStrategy()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        searchStrategy.setSearchStrategy(ImageSearchStrategy)
        
        serach_btn.setOnClickListener { 
            searchStrategy.search()
        }
    }
    
    fun setSearchStrategy(_searchStrategy :SearchStrategy){
    	searchStrategy = _searchStrategy
    }
}

위처럼 간단하게 인터페이스 클래스의 search() 메서드 호출을 통해 구현이 가능해졌다. 전체/이미지/뉴스 등 탭이 바뀔 경우 setSearchStrategy() 메서드를 통해 전략을 바꾸기만 하면 된다. 이후 학습할 상태 패턴과 다르게 전략 패턴은 외부 객체인 MainActivity에서 실행할 객체(전략)을 지정해준다. 상태 패턴은 수행할 객체(상태)가 내부에서 결정이 된다.

 

 

요약

  • 각각 서로 다른 유사한 행위를 하는 코드가 존재할 경우 사용 가능
  • 공통적인 행위를 정의한 인터페이스 클래스를 만든다
  • 인터페이스 클래스를 상속받아 필수 메서드를 구현한다.
  • Context에서는 인터페이스 클래스 타입의 변수를 선언하여 때에 따라 전략 객체를 교체하면서 실행한다.