알고리즘 군을 정의하고 캡슐화해서 각각의 알고리즘군을 수정해서 쓸 수 있게 해준다.
클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있다.
즉, 객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화하는 행위를 말한다.
만일 오리가 있다고 해보자. 오리의 종류에는 여러가지가 존재한다.
꽥꽥 우는 오리가 있을 것이고, 장난감 오리처럼 울지 못하는 오리, 끽끽 우는 오리..등등 많을 것이다.
이러한 부분을 그냥 구현해보면 다음과 같다.
public abstract class Duck {
abstract void swim();
abstract void quack();
abstract void display();
}
public class RedheadDuck extends Duck{
@Override
public void swim() {
/** 구현 **/
}
@Override
public void display() {
/** 구현 **/
}
@Override
public void quack() {
/** 구현 **/
}
}
public class RubberDuck extends Duck{
@Override
public void swim() {
/** 구현 **/
}
@Override
public void display() {
/** 구현 **/
}
@Override
public void quack() {
/** 구현 **/
}
}
이런식으로 새로운 오리가 탄생할 때 마다 swim, display, quack을 구현해야한다.
만약, 같은 꽥꽥우는 오리가 생겨도 똑같이 구현해야하는 코드의 중복이 생기게 되는 문제도 생긴다.
그리고 울지 못 하는 오리가 생겨도 quack()
이라는 메소드를 상속받고 구현해야하는 문제도 생긴다.
여기서 달라지는 부분을 찾아내고, 달라지지 않는 부분을 분리한다. 라는 디자인 원칙을 적용해 진행해보자.
달라지는 부분은 각각 swim, display, quack과 같은 부분일 것이다.
달라지지 않는 부분은 오리라는 특성은 달라지지 않을 것이다.
그렇다면 오리라는 클래스는 냅두고, 달라지는 부분을 따로 나타내보자.
우리는 달라지는 부분을 따로 캡슐화해야한다.
public abstract class Duck {
private QuackStrategy quackStrategy;
private SwimStrategy swimStrategy;
abstract void display();
public void performQuack() {
quackStrategy.quack();
}
public void performSwim() {
swimStrategy.swim();
}
public void setSwimStrategy(SwimStrategy swimStrategy) {
this.swimStrategy = swimStrategy;
}
public void setQuackStrategy(QuackStrategy quackStrategy) {
this.quackStrategy = quackStrategy;
}
}
public class RedheadDuck extends Duck{
@Override
public void display() {
/** 구현 **/
}
}
public interface QuackStrategy {
void quack();
}
public interface SwimStrategy {
void swim();
}
이렇게 우는 부분과 헤엄치는 부분을 따로 뺐다.
이를 구현하는 클래스를 만들자.
public class Squack implements QuackStrategy{
@Override
public void quack() {
System.out.println("꽥꽥");
}
}
public class SwimNoWay implements SwimStrategy{
@Override
public void swim() {
System.out.println("수영을 못 해요..");
}
}
이제 작동하는 오리를 만들어보자.
public class Main {
public static void main(String[] args) {
Duck redDuck = new RedheadDuck();
redDuck.setQuackStrategy(new Squack());
redDuck.setSwimStrategy(new SwimNoWay());
redDuck.performQuack();
redDuck.performSwim();
}
}
나중에 같은 꽥꽥우는 오리를 추가하고 싶으면 Squack
을 받아서 진행하면 된다. ⇒ 코드의 중복성이 사라진다.
나중에 오리가 추가 되었을 때도 새로운 기능이 추가되면 QuackStrategy
인터페이스를 상속받아 새롭게 추가하면 된다. ⇒ OCP를 만족한다.
참고
헤드퍼스트 디자인 패턴