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

전략 패턴
홍윤's avatar
Aug 13, 2024
(디자인 패턴)전략 패턴(Strategy Pattern)
💡
전략 패턴(Strategy Pattern)은 객체 지향 프로그래밍에서 행동 패턴 중 하나로, 알고리즘을 캡슐화하여 클라이언트가 알고리즘을 변경할 수 있도록 하는 패턴입니다. 이 패턴은 알고리즘을 개별적인 클래스로 분리하여, 런타임에 알고리즘을 교체할 수 있게 해줍니다. 주요 개념은 다음과 같습니다:
 

주요 개념

  1. 전략(Strategy) 인터페이스:
      • 공통의 알고리즘 인터페이스를 정의하며, 알고리즘을 수행하는 메소드를 포함합니다.
  1. 구체적인 전략(ConcreteStrategy) 클래스:
      • 전략 인터페이스를 구현하여 실제 알고리즘을 제공하는 클래스입니다. 다양한 알고리즘이 각기 다른 전략 클래스에 구현됩니다.
  1. 컨텍스트(Context) 클래스:
      • 전략 객체를 사용하는 클래스입니다. 클라이언트로부터 전략 객체를 받아 알고리즘을 수행합니다.

장점

  • 알고리즘의 캡슐화: 알고리즘을 개별적인 클래스로 분리하여 클라이언트 코드와 알고리즘 구현을 독립적으로 변경할 수 있습니다.
  • 유연한 알고리즘 교체: 런타임에 알고리즘을 동적으로 변경할 수 있어 다양한 요구에 유연하게 대응할 수 있습니다.
  • 코드 재사용: 공통의 인터페이스를 통해 다양한 알고리즘을 재사용할 수 있습니다.
  • 기존 코드 수정 없음: 알고리즘을 교체하더라도 기존 코드를 수정할 필요가 없습니다.
  • 추상화 의존: 구체적인 알고리즘에 의존하지 않고, 추상적인 전략 인터페이스에 의존합니다.
Soild란?
SOLID는 객체 지향 프로그래밍에서 클래스 설계의 원칙들을 정의하는 다섯 가지 원칙의 약어입니다. 이 원칙들은 소프트웨어의 유지보수성과 확장성을 향상시키기 위해 설계되었습니다. 각각의 원칙은 다음과 같습니다:
  1. 단일 책임 원칙 (Single Responsibility Principle, SRP):
      • 정의: 클래스는 하나의 책임만 가져야 하며, 그 책임은 완전히 캡슐화되어야 합니다.
      • 의미: 하나의 클래스가 너무 많은 책임을 지게 되면, 변경이 필요할 때 모든 관련 코드를 수정해야 하며, 이로 인해 코드가 복잡해지고 유지보수가 어려워질 수 있습니다.
  1. 개방-폐쇄 원칙 (Open/Closed Principle, OCP):
      • 정의: 소프트웨어 엔티티(클래스, 모듈 등)는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 합니다.
      • 의미: 기능을 추가할 때 기존 코드를 변경하지 않고도 확장할 수 있어야 합니다. 이는 코드의 안정성을 높이고, 기존 기능에 대한 영향을 최소화합니다.
  1. 리스코프 치환 원칙 (Liskov Substitution Principle, LSP):
      • 정의: 자식 클래스는 부모 클래스의 기능을 대체할 수 있어야 하며, 부모 클래스의 인스턴스를 자식 클래스의 인스턴스로 대체해도 프로그램의 동작이 올바르게 유지되어야 합니다.
      • 의미: 자식 클래스가 부모 클래스를 대체할 수 있어야 하며, 부모 클래스가 요구하는 계약을 완전히 지켜야 합니다. 이를 통해 상속 구조가 안전하게 유지됩니다.
  1. 인터페이스 분리 원칙 (Interface Segregation Principle, ISP):
      • 정의: 클라이언트는 자신이 사용하지 않는 메소드에 의존하지 않아야 합니다.
      • 의미: 큰 인터페이스를 여러 개의 작은 인터페이스로 나누어, 각 클라이언트가 자신에게 필요한 메소드만을 갖도록 해야 합니다. 이를 통해 클래스가 불필요한 기능에 의존하지 않게 됩니다.
  1. 의존 역전 원칙 (Dependency Inversion Principle, DIP):
      • 정의: 고수준 모듈(상위 모듈)은 저수준 모듈(하위 모듈)에 의존해서는 안 되며, 두 모듈 모두 추상화에 의존해야 합니다. 또한, 추상화는 세부 사항에 의존하지 않아야 하고, 세부 사항이 추상화에 의존해야 합니다.
      • 의미: 고수준 모듈과 저수준 모듈 간의 의존성을 줄이고, 두 모듈이 인터페이스나 추상 클래스를 통해 의존하도록 설계하여 시스템의 유연성을 높입니다.
이 원칙들은 객체 지향 설계를 보다 견고하고 유지보수하기 쉽게 만들어주며, 코드를 잘 구조화하고 재사용 가능하도록 돕습니다.

1. “Solid” 이용한 전략 패턴 연습 예제 및 해설

  1. Main
package ex01; /** * * Animal 생성 (abstract) * 타입 일치(다형성) = 쥐(동물), 호랑이(동물) * 문지기한테 DIP만 지켜주면 됨 */ abstract class Animal{ abstract void 쫒아내(); } public class App { public static void main(String[] args) { Mouse m1 = new Mouse(); Tiger t1 = new Tiger(); Doorman d1 = new Doorman(); d1.쫒아내(m1); } }
  • ‘Animal’은 추상 클래스 이며, 그 하위 클래스인 ‘Mouse’ 와 ‘ Tiger’ 는 ‘ Animal’의 추상 메소드 ‘쫓아내’를 각각 구현하고 있다.
  • ‘App’ 클래스의 ‘main’ 메소드에서 ‘Mouse’, ‘Tiger’ , ‘Doorman’ 객체가 생성됩니다.
  • ‘Doorman’ 객체는 ‘쫓아내’ 메소드를 사용하여 ‘Mouse’객체를 쫓아내는 동작을 수행한다.
  • 이 프로그램 코드는 동물 객체를 관리하고, 특정 객체를 쫓아내는 기능은 가진 간단한 예제다.
  1. Mouse
package ex01; public class Mouse extends Animal{ private String name = "쥐"; @Override void 쫒아내() { } public String getName() { return name; } }
Mouse’클래스는 ‘Animal’ 클래스를 상속을 받아 ‘name’ 이라는 ‘쥐’ 값을 가진 변수를 포함하고 있다.
  • ‘Mouse’클래스는 ‘쫓아내()’ 메소드를 재정의 했지만 현재 아무런 동작도 정의 하지 않고있다.
  • ‘getName()’의 메소드를 통해 ‘name’의 변수의 값을 가지고 있습니다.
3.Tiger
package ex01; public class Tiger extends Animal{ private String name = "호랑이"; @Override void 쫒아내() { } public String getName() { return name; } }
  • ‘Tiger’클래스는 ‘Animal’ 클래스를 상속을 받아 ‘name’ 이라는 ‘쥐’ 값을 가진 변수를 포함하고 있다.
  • ‘Tiger’클래스는 ‘쫓아내()’ 메소드를 재정의 했지만 현재 아무런 동작도 정의 하지 않고있다.
  • ‘getName()’의 메소드를 통해 ‘name’의 변수의 값을 가지고 있습니다.
☆4.Doorman
package ex01; /** * 문지기한테 DIP만 지켜줘라는 뜻은 * 하나만 지키게 하라 즉 Animal이라는 부모에 속한 쥐, 호랑이들을 * App인 큰 틀에서 책임지게 만들어라는 뜻! * * */ public class Doorman extends App{ // 쥐 출입금지 public void 쫒아내(Mouse m) { System.out.println(m.getName()+"쫒아내"); } }
  • ‘Doorman’클래스는 ‘App’클래스 상속받아, 특정’Mouse’ 객체를 쫓아내는 역활을 한다.
  • 의존 역전 원칙(DIP)을 지키키 위해, 구체적인 하위 클라스(’Mouse’)를 직접 다루기 보다 ‘Animal’부모 클래스에 의존하도록 설계
  • ‘쫓아내’ 메소드는 ‘Mouse’ 객체를 받아 이름과 함께 ‘쫓아내’라는 메세지를 출력 한다.
  • 이 코드에서 ‘Mouse’ 객체만 처리하고 있지만, 의존성 역전 원칙을 적용하면 ‘Doorman’클래스가 ‘Animal’클래스에 의존하고 여러 종류의 ‘Animal’ 객체(’Mouse’,’Tiger’)를 동일한 방식으로 처리 할 수 있게 설계 되었다.
Share article

Uni