IT/다자인 패턴

3.5 전략 패턴(Stragety Pattern).....행동 패턴(Behavioral Pattern) 중

원창연 2022. 8. 13. 15:59
스트래티지 패턴(Strategy pattern)은 각각을 캡슐화하여 교환해서 사용할 수 있도록 만든다. 
스트래티지를 활용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.
즉, 행위를 클래스로 캡슐화 하여 동적으로 행위를 바꾸어도 코드가 복잡해 지지 않도록 한다.
여기서의 패턴 이름과 같이 전략을 쉽게 바꾸도록 해주는 디자인 패턴이다.
ex) sorting 알고리즘 여러개가 있는데 이중 하나를 고르려고 할 때

이때, 스트래티지 패턴을 이용하면 condition statement가 현저히 줄어드는 장점이 있다.


디자인 원칙
코드에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리시킨다. (달라지는 부분을 찾아서 나머지 코드에 영향을 주지 않도록 "캡술화")
상속보다는 구성을 활용한다.(상속 보다는 객체의 합성을 중요시 하자)
상속보다는 구성을 활용한다. 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.
Strategy
  외부에서 동일한 방식으로 알고리즘을 호출 할 수 있도록 명시해둔 인터페이스
ConcreteStrategy
  스트래티지 인터페이스에서 명시해둔 코드를 실제로 구현한 클래스
Context
    스트래티지 패턴을 이용하는 역할을 수행하는 추상 클래스필요에 따라 동적으로 구체적인 전략을 바꿀 수 있도록 하기위해 setter 집약 관계 메서드를 제공한다.
집약 관계
- 참조값을 인자로 받아 필드를 세팅하는 경우- 전체 객체의 라이프타임과 부분 객체의 라이프 타임은 독립적이다.- 즉, 전체 객체가 메모리에서 사라진다 해도 부분 객체는 사라지지 않는다.

Stragety Pattern을 오리 게임을 만드는 것을 이용하여 한번 생각해보자.


Strategy, ConcreteStrategy를 통해 fly, quack에 대한 행동을 먼저 만들어보자

외부에서 명세 Strategy FlyBehavior를 통해 ContreateStartegy인 FlyWithWings, FlyNoWay 행동을 먼저 만들자

package com.patterns.StrategyPattern;

public interface FlyBehavior {
	public void fly();
}
package com.patterns.StrategyPattern;

public class FlyWithWings implements FlyBehavior {
	@Override
	public void fly() {
		System.out.println("날고 있습니다.");
	}
}
package com.patterns.StrategyPattern;

public class FlyNoWay implements FlyBehavior {

	@Override
	public void fly() {
		System.out.println("날지 못하고 있습니다.");
	}

}

마찬가지로 외부에서 명세 Strategy QuackBehavior를 통해 ContreateStartegy인 Quack, NoQuack 행동을 만들자

package com.patterns.StrategyPattern;

public interface  QuackBehavior {
	public void quack();
}
package com.patterns.StrategyPattern;

public class Quack implements QuackBehavior{

	@Override
	public void quack() {
		  System.out.println("꽥꽥");
	}

}
package com.patterns.StrategyPattern;

public class NoQuack  implements QuackBehavior {

	@Override
	public void quack() {
		System.out.println("소리를 못냅니다.");
	}

}
그리고 Duck 추상 클래스를 만들어준다.
package com.patterns.StrategyPattern;

public abstract class Duck {

	FlyBehavior 	flyBehavior;
	QuackBehavior 	quackBehavior;

	public void swim() {
		System.out.println("물에 떠있습니다.");
	}

	public abstract void display();

	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}

	public void getFlyBehavior() {
		flyBehavior.fly();
	}

	public void setQuackBehavior(QuackBehavior quackBehavior) {
		this.quackBehavior = quackBehavior;
	}

	public void getQuackBehavior() {
		quackBehavior.quack();
	}
}​

실제 오리객체인 청둥오리객체 생성

package com.patterns.StrategyPattern;

public class MallardDuck extends Duck {

	public MallardDuck() {
		flyBehavior = new FlyWithWings();
		quackBehavior = new Quack();
	}

	@Override
	public void display() {
		System.out.println("청둥오리 입니다.");
	}

}

 

개발내용 테스트

package com.patterns.StrategyPattern;

public class DuckGame {
	public static void main(String[] args) {
		Duck mallard = new MallardDuck();
		mallard.getQuackBehavior();
		mallard.getFlyBehavior();
		System.out.println();
		mallard.setFlyBehavior(new FlyNoWay());
		mallard.getQuackBehavior();
		mallard.getFlyBehavior();
		System.out.println();
		mallard.setQuackBehavior(new NoQuack());
		mallard.getQuackBehavior();
		mallard.getFlyBehavior();
	}
}

 마지막으로 실제 오리 게임에서

오리 객체를 생성해주면 오리는 fly, quack에 대해 기본 상태를 가지게 되고
지금부터는 코드의 복잡함 없이 각 클래스에서 필요한 메서드만 호출하면 되고
FlyBehavior, QuackBehavior쪽에서는 그에 맞는 행동만 정의하고 구현해주면 된다.

참고 원문: https://www.crocus.co.kr/1526?category=337544