전략패턴(HAS-A의 장점)
알고리즘의 군을 정의하고 캡슐화해주며, 서로 언제든지 바꿀 수 있도록 해줌
느슨한 연결이 가능하고 동적 변화에 유리하게 설계가능
다형성을 보장 추가와 변형에 유리함
HAS-A 와 DIP 의존관계 주입을 이용
객체 생성에 필요한 다양한 알고리즘을 필요할때 실행시간에 바꾸어 사용하고싶다면?
생성을 담당하는 메서드를 캡슐화하고 has-a와 dip를 이용한다.
내부로직을 들어내지 않고 은닉화 할수있으며 동적처리가 가능
아래 코드에서 fly() 기능을 사용하고싶다. interface? 상속?
//부모
abstract class Duck{
void quack(){ //공통 사용 메서드
..
}
abstract void color(); //자손에게 각자 재정의 위임
}
//중간 클래스
class YellowDuck extends Duck{
void color(){
sout("하위 노란 오리들을 위한 중간 클래스");
}
}
//자손 1
class MDuck extends Duck{
...
}
//자손2
class GDuck extends Duck{
...
}
상속의 문제: 부모에 정의된 모든 메소드가 모든 자식에 적합하지 않을 수 있음
자손에서 재정의 하는 방식으로 해결
대부분의 자손에서 적합하지 않으면 abstract 메서드로 재정의를 서브클래스(자손)에게 위임
동일하게 해결하는 서브클래스들이 있다면 중간 클래스 도입
인터페이스의 문제: 구현클래스마다 재정의해야함으로 코드중복을 피할수 없음
특정기능을 제공하는 클래스와 아닌 클래스를 구분할수있다.
인터페이스 자체에 메서드를 정의하더라도 오버라이딩 없이 동적 변화를 제공하기 힘들다.
전략패턴으로 해결! : 동적변화기법
[전략패턴 관계도]
Strategy 인터페이스: 전략을 이용하기 위한 인터페이스 제공 Concrete Strategy 클래스: 다수가 제공되며, 구체적인 전략이구현되어 있는 클래스 Client 클래스(context 클래스): 전략을 실제 활용하는 클래스
[사용시기]
관련있는 클래스들이 행위만 다를 경우 fly()
알고리즘의 다양한 변형이 필요한 경우
[장점]
포함관계(has-a)와 다형성, 추상화에 느슨한 의존을 이용하여 동적 변화를 제공하면서 코드 중복을 피할수있다.
실행시간에 DI를 변경할수있다.
객체의 생성 라이프사이클을 조절가능
새로운 오리타입의 생성이 용이해진다.
새로운 행위의 추가가 쉽다
[단점]
전략이 클라이언트의 상태가 필요한경우 양방향 의존관계가 성립되어 위험하다.
[관련 패턴]
전략 클래스 객체가 불필요하게 많이 생성되는 것을 피하기 위해 싱글톤으로 구현하는 경우가 많음
싱글톤이 아니라면 호출마다 객체 생성
- 각 행위들을 인터페이스로 구분하여 정의한다.
- 구현클래스들은 포함관계로 객체들을 생성자 주입 받아서 사용한다.
//추상클래스 부모 abstract class Duck{ //has-a 이용 private FlyBehavior fb; private QuackBehavior qb; //생성자 DI: 추상클래스도 생성자가 있어야한다!!!!!!!!!!!! /** 1. 자식에게 오버라이딩을 강제하기 위해 미완성으로 선언하는것뿐 2. 생성자가 존재한다. 자손에서 생성자 super를 사용할수있다. 3. 직접 생성은 불가 //미완성 메서드 존재할가능성 있기 때문 */ public Duck(FlyBehavior fb,QuackBehavior qb){ this.fb=fb; this.qb=qb; } //주입된 구현클래스를 활용 void quack(){ qb.quack(); } abstract void color(); } //자손 class MDuck extends Duck{ //부모가 abstract: 자손에서 주입 public MDuck(FlyBehavior fb,QuackBehavior qb){ super(fb,qb); } } //main /** 자유롭게 DI하여 갈아 끼울수있다. */ public class main { public static void main(String[] args) { FlyBehavior fb = new FlyNoWay(); //다형성 활용: 실행시간에 언제든 갈아끼울수있다. QuackBehavior qb = new Squeak(); Duck d = new MDuck(fb,qb); //DI d.quack(); // "sqeak!!" } }
보통 Has-a는 is-a보다 좋다
- 비교적 유연한 해결책을 가져다 줌
- 실행시간에 행위변경 가능
관련 리펙토링
- 상황에 맞게 선택하여 사용
- 클라이언트의 크기를 줄일수있다.
'개발자 준비 > 디자인패턴 & 아키텍쳐' 카테고리의 다른 글
장식자 패턴(Decorator) (0) | 2021.12.29 |
---|---|
관찰자(Observer) 패턴 (0) | 2021.12.29 |
[번외] UML 이해하기 (0) | 2021.12.29 |
OOP 설계 원리 (0) | 2021.12.29 |
OOP 개요 (0) | 2021.12.29 |