Java

스트래티지 패턴(Strategy Pattern)

it's woo 2021. 9. 17. 04:00

스트래티지 패턴이란?

같은 종류의 작업을 하는 알고리즘을 정의하고

각 알고리즘을 캡슐화, 그리고 알고리즘들을 서로 바꿔 사용할 수 있도록 한다.

알고리즘을 사용하는 클라이언트로부터 독립적을 알고리즘을 바꿔서 적용시킬 수 있도록 한다.

 

말이 너무 어렵다.

널리 알려져 있는 유명한 예시를 보자

오리라는 클래스를 만들고 이것을 상속받는 여러 오리들을 만들어 보자

 

class Duck {
	void quack() {
		System.out.println("quack");
	}
	
	void swin() {
		System.out.println("swimmin");
	}
	
	void fly() {
		System.out.println("flying");
	}
	void display() {
		System.out.println("Duck");
	}
}

class MallardDuck extends Duck {
	@Override
	void display() {
		System.out.println("MallardDuck");
	}
}

class RubberDuck extends Duck {
	@Override
	void quack() {
		System.out.println("squeak");
	}
	@Override
	void display() {
		System.out.println("RubberDuck");
	}
	@Override
	void fly() {
		System.out.println("cannot fly");
	}
}

Duck 클래스를 상속받아 MalladrdDuck과 RubberDuck을 만들었다.

 

문제는 무엇일까?

RubberDuck은 장난감 오리여서 날 수가 없지만 상속을 받아 fly라는 메서드를 가지게 된다.

 

해결방안?

위 코드는 오버라이드를 하여 날 수 없음을 표현하였다.

오버라이드 하는 것이 좋은 선택일까?

만약 수십 개의 날지 못하는 오리 장난감이 있다면 각각 오버라이드를 해주어야 한다.

매우 비효율적인 작업이다.

 

fly메서드와 quack메서드를 가지는 interface를 만들면 어떨까?

class Duck {
	void swim() {
		System.out.println("swimming");
	}
	void display() {
		System.out.println("Duck");
	}
}

interface Flyable {
	void fly();
}

interface Quackable{
	void quack();
}


class MallardDuck extends Duck implements Flyable, Quackable{
	void display() {
		System.out.println("MallardDuck");
	}
	public void quack() {
		System.out.println("quack");
	}
	public void fly() {
		System.out.println("flying");
	}
}

class RedheadDuck extends Duck implements Flyable, Quackable{
	void display() {
		System.out.println("RedheadDuck");
	}
	public void quack() {
		System.out.println("quack");
	}
	public void fly() {
		System.out.println("flying");
	}
}

class RubberDuck extends Duck implements Quackable{
	public void quack() {
		System.out.println("squeak");
	}
	void display() {
		System.out.println("RubberDuck");
	}
}

 

RubverDuck은 Flyable을 상속받지 않아서 문제가 해결된 것 같다.

하지만 다른 문제가 있다.

RedheadDuck 클래스와 MallardDuck 클래스는

quack 메서드와 fly 메서드를 반복해서 작성해줘야 돼 비효율적이다.

default 메서드를 생각해볼 수 있다.

하지만 default 메서드에 변화나 오류가 있다면 default메서드를 사용하는 모든 부분을 찾아 수정해 주어야 한다.

 

스트래티지 패턴

상황마다 수정이 필요한 부분과 그렇지 않은 부분으로 나눈다.

위 오리 클래스중 오리들마다 바뀌는 부분은 flt와 quack 부분임으로

이 두 부분을 분리하여 클래스 만듭니다.

특정 행동을 Duck 클래스에서 구현하는 것이 아니라 독립적으로 새로운 클래스를 만들어서 구현하고

Duck 클래스는 클래스나 구현한 인터페이스를 사용하여 Duck과 무관하게 만들어집니다.