본문 바로가기
1분 테크

전략패턴(Strategy) 패턴

by 1223v 2024. 6. 10.

전략패턴이란?


전략 패턴은 실행 중에 알고리즘 전략을 선택해서 객체 동작을 실시간으로 바뀌도록 할 수 있게 하는 행위 디자인 패턴이다.

여기서 전략이란 일종의 알고리즘이 될 수도 있고, 기능이나 동작이 될 수 있는 특정한 목표를 수행하기 위한 계획을 말한다.

조금 어려운 느낌일지도 모른다.

간단하게 생각하면 위 사진과 같이 검색창을 구현하는 상황을 생각하면 된다.

 

보통은 위 사진과 같이 클릭이 있어나면 그 클릭의 모드에 따라 조건문을 거쳐 메소드를 실행할 것이다.

하지만 이는 수평적 확장을 진행할 때, 기능이 추가될수록 조건문이 늘어나고 기존의 코드를 수정해야한다는 단점이 존재한다.

 

 

즉, 고수준 모듈이 기능이라는 저수준 모듈에 의존하여 코드의 주도권을 뺏기는 상황이라 볼 수 있다.

이는 객체 지향 5원칙에 OCP와 DIP를 못지킨 사례라 볼 수 있다.

 

이를 해결한 방식이 전략 패턴이라 볼 수 있다.

 

요약하자면, 어떤 일을 수행하는 알고리즘이 전체 , 이미지, 뉴스, 지도 와 같이 여러가지 일때, 동작들을 미리 전략으로 정의함으로써 손쉽게 전략을 교체할 수 있는 알고리즘 변형이 빈번하게 필요한 경우에 적합한 패턴이다.

전략 패턴 구조

  • 전략 알고리즘의 객체들 : 알고리즘, 행위, 동작을 객체로 정의한 구현체
  • 전략 인터페이스 : 모든 전략 구현체에 대한 공용 인터페이스
  • 컨텍스트(Context) : 알고리즘을 실행해야 할 때마다 해당 알고리즘과 연결된 전략 객체의 메소드를 호출
  • 클라이언트 : 특정 전략 객체를 컨텍스트에 전달함으로써 전략을 등록하거나 변경하여 전략 알고리즘을 실행한 결과를 누린다.

프로그래밍에서의 컨텍스트란 콘텐츠를 담는 무언인가를 뜻하고, 어떤 객체를 핸들링하기 위한 접근수단이다.

 

전략패턴은 OOP의 집합

 

전략패턴

  • 동일 계열의 알고리즘군을 정의하고 → 전략 구현체로 정의
  • 각각의 알고리즘을 캡슐화하여 → 인터페이스로 추상화
  • 상호교환이 가능하도록 만든다. → 합성으로 구성
  • 알고리즘을 사용하는 클라이언트와 상관없이 독립적으로 → 컨텍스트 객체 수정 없이
  • 알고리즘을 다양하게 변경 → 메소드를 통해 전략 객체를 실시간으로 변경함으로써 전략 변경

결론적으로 요약해보면 자바의 객체지향 원칙 SOLID의 OCP, DIP, 합성, 다형성, 캡슐화 등 OOP 기술들의 총 집합 버전이라고 생각하면 된다.

 

이제부터 코드로 살펴보자

public class SearchButton {
	private MyProgram myProgram;
	
	public SearchButton(MyProgram _myProgram) {
		myProgram = _myProgram;
	}
	
	private SearchStrategy searchStrategy = new SearchStrategyAll();
	
	public void setSearchStrategy(SearchStrategy _searchStrategy) {
		searchStrategy = _searchStrategy;
	}
	
	public void onClick() {
		searchStrategy.search();
	}
}

 

interface SearchStrategy {
	public void search();
}

class SearchStrategyAll implements SearchStrategy {
	public void search() {
		System.out.println("Search ALL");
	}
}

class SearchStrategyImage implements SearchStrategy {
	public void search() {
		System.out.println("IMAGE");
	}
}

class SearchStrategyNews implements SearchStrategy {
		public void search() {
			System.out.println("NEWS");
		}
}

class SearchStrategyMap implements SearchStrategy {
	public void search () {
		System.out.println("MAP");
	}
}
	
public class MyProgram {

	private SearchButton searchButton = new SearchButton(this);
	
	public void setModelAll() {
		searchButton.setSearchStrategy(new SearchStrategyAll());
	}
	
	public void setModelImage() {
		searchButton.setSearchStrategy(new SearchStrategyImage());
	}
	
	public void setModeNews() {
		searchButton.setSearchStrategy(new SearchStrategyNews());
	}
	
	public void setModeMap() {
		searchButton.setSearchStrategy(new SearchStrategyMap());
	}
}

결제시스템 예제

// 전략 - 추상화된 알고리즘
interface PaymentStrategy {
	void pay(int amount);
}

class KAKAOCardStrategy implements PaymentStrategy {
	private String name;
	private String cardNumber;
	private String cvv;
	private String dateOfExpiry;
	
	public KAKAOCardStrategy(String nm, String ccNum, String cvv, String expiryDate){
		this.name = nm;
		this.cardNumber = ccNum;
		this.cvv = cvv;
		this.dateOfExpiry = expiryDate;
	}
	
	@Override
	public void pay(int amount) {
		System.out.println(amount + " 원 paid using KAKAOCard");
	}
	
}

class LUNACardStrategy implements PaymentStrategy [
	private String emailId;
	private String password;
	
	public LUNACardStrategy(String email, String pwd) {
		this.emailId = email;
		this.password = pwd;
	}
	
	@Override
	public void pay(int amount) {
		System.out.println(amount + " 원 paid using LUNACard");
	}
}
	

// 컨텍스트 - 전략을 등록하고 실행
class ShoppingCart {
	List<Item> items;
	
	public ShoppingCart() {
		this.items = new ArrayList<Item>();
	}
	
	public void addItem(Item item) {
		this.items.add(item);
	}
	
	
	// 전략을 매개변수로 받아서 바로바로 전략을 실행
	public void pay(PaymentStrategy paymentMethod) {
		int amount = 0;
		for (Item item : items) {
			amount += item.price;
		}
		paymentMethod.pay(amount);
	}
}
class Item {
	public String name;
	public int price;
	
	public Item(String name, int cost) {
		this.name = name;
		this.price = cost;
	}
}

//클라이언트 - 전략 제공/설정
class User {
	public static void main(String[] args) {
		// 쇼핑카트 전략 컨텍스트 등록 
		ShoppingCart cart = new ShoppingCart();
		
		//쇼핑 물품
		Item A = new Item("맥북 프로", 10000);
		Item B = new Item("플레이스테이션" , 30000);
		card.addItem(A);
		card.addItem(B);
		
		//LUNACard 결제 전략 실행
		cart.pay(new LUNACardStrategy("kundol@example.com", "pukubababo"));
		
		//KAKAOBank로 결제 전략 실행
		cart.pay(new KAKAOCardStrategy("Ju hongchul", "123456789", "123", "12/01"));
	}	
}

 

전략 패턴 특징

 

전략 패턴 사용 시기

  • 전략 알고리즘의 여러 버전 또는 변형이 필요할 때 클래스화를 통해 관리
  • 알고리즘 코드가 노출되어서는 안되는 데이터에 액세스하거나 데이터를 활용할때 (캡슐화)
  • 알고리즘의 동작이 런타임에 실시간으로 교체되어야 할 때

전략 패턴 주의점

  • 알고리즘이 많아질수록 관리해야할 객체의 수가 늘어난다는 단점이 있다.
  • 만일 어플리케이션 특성이 알고리즘에 많지 않고 자주 변경되지 않는다면, 새로운 클래스와 인터페이스를 마들어 프로그램을 복잡하게 만들 이유가 없다.
  • 개발자는 적절한 전략을 선택하기 위해 전략간의 차이점을 파악하고 있어야 한다.

실무에서 사용되는 전략 패턴

  • Collections의 sort() 메서드에 의해 구현되는 compare() 매서드 이용
  • javax.servlet.http.HttpServlet에서 service() 메서드와 모든 doXXX() 메서드에 이용
  • javax.servlet.Filter의 doFilter() 메서드에 이용전략패턴이란?

'1분 테크' 카테고리의 다른 글

Enum  (0) 2024.06.25
싱글톤(Singleton) 패턴  (0) 2024.05.31
정규화(Normalization)  (0) 2024.03.31

댓글