목차
- ☆ 표시가 붙은 부분은 스터디 중 나온 얘기 혹은 제 개인적인 생각이나 제가 이해한 방식을 적어놓은 것으로, 책에 나오지 않는 내용입니다. 따라서 책에서 말하고자 하는 바와 다를 수 있습니다. 또한 책에는 따로 Step으로 나오지 않습니다. 설명의 편의를 위해 임의로 나눈 것 입니다.
- 모든 이미지의 출처는 헤드퍼스트 디자인패턴 개정판(한빛미디어) 입니다.
전략 패턴 (Strategy Pattern)
코드 링크 : github
Step 1. 초기 코드
class Duck {
public void quack() {
System.out.println("Quack!");
}
public void swim() {
System.out.println("Swim!");
}
public void display() {
System.out.println("Display!");
}
}
class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("MallardDuck display!");
}
}
class RedheadDuck extends Duck {
@Override
public void display() {
System.out.println("RedheadDuck display!");
}
}
class RubberDuck extends Duck {
@Override
public void quack() {
System.out.println("Squeak!");
}
@Override
public void display() {
System.out.println("RubberDuck display!");
}
}
Step 2. 오리가 날 수 있어야 한다!
일부 Duck들만 fly()를 추가하려고 하는데
Duck에 추가했더니 당연히 전부 적용되버림.
러버덕은 날면 안되니깐 아무것도 안하게 오버라이드를 해줘야 한다.
class Duck {
public void quack() {
System.out.println("Quack!");
}
public void swim() {
System.out.println("Swim!");
}
public void display() {
System.out.println("Display!");
}
public void fly() {
System.out.println("Fly!");
}
}
class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("MallardDuck display!");
}
}
class RedheadDuck extends Duck {
@Override
public void display() {
System.out.println("RedheadDuck display!");
}
}
class RubberDuck extends Duck {
@Override
public void quack() {
System.out.println("Squeak!");
}
@Override
public void display() {
System.out.println("RubberDuck display!");
}
@Override
public void fly() {
// do nothing
}
}
Step 3. 가짜 오리 추가!
가짜 오리(DecoyDuck)을 추가하려고 했더니
quack, fly 둘 다 아무것도 안해야됨;
이렇게 상속으로 처리하는건 해결책이 아닌 것 같음.
이후에 오리가 추가될 때 마다 fly랑 quack 전부 살펴보고 상황에 따라 오버라이드 해야됨 ㅠ
class Duck {
public void quack() {
System.out.println("Quack!");
}
public void swim() {
System.out.println("Swim!");
}
public void display() {
System.out.println("Display!");
}
public void fly() {
System.out.println("Fly!");
}
}
class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("MallardDuck display!");
}
}
class RedheadDuck extends Duck {
@Override
public void display() {
System.out.println("RedheadDuck display!");
}
}
class RubberDuck extends Duck {
@Override
public void quack() {
System.out.println("Squeak!");
}
@Override
public void display() {
System.out.println("RubberDuck display!");
}
@Override
public void fly() {
// do nothing
}
}
class DecoyDuck extends Duck {
@Override
public void display() {
System.out.println("DecoyDuck display!");
}
@Override
public void quack() {
// do nothing
}
@Override
public void fly() {
// do nothing
}
}
Step 4. 상속대신 인터페이스?
상속은 아닌 것 같으니 인터페이스를 추가해서 해결해보려 하는 과정임.
문제는 기존에 상속해서 fly랑 quack 잘 쓰고 있던 오리들도
구조가 바뀌면서 전부 fly랑 quack을 구현해야 됨;
따라서 전체적인 오리들을 전부 손대야 하는대다가 코드중복이 발생해버림.
이것도 아닌 것 같음.
class Duck {
public void swim() {
System.out.println("Swim!");
}
public void display() {
System.out.println("Display!");
}
}
interface Flyable {
public void fly();
}
interface Quackable {
public void quack();
}
class MallardDuck extends Duck implements Flyable, Quackable {
@Override
public void display() {
System.out.println("MallardDuck display!");
}
@Override
public void fly() {
System.out.println("Fly!");
}
@Override
public void quack() {
System.out.println("Quack!");
}
}
class RedheadDuck extends Duck implements Flyable, Quackable {
@Override
public void display() {
System.out.println("RedheadDuck display!");
}
@Override
public void fly() {
System.out.println("Fly!");
}
@Override
public void quack() {
System.out.println("Quack!");
}
}
class RubberDuck extends Duck implements Quackable {
@Override
public void quack() {
System.out.println("Squeak!");
}
@Override
public void display() {
System.out.println("RubberDuck display!");
}
}
class DecoyDuck extends Duck {
@Override
public void display() {
System.out.println("DecoyDuck display!");
}
}
Step 5. 전략 패턴 적용! 바뀌는 부분과 바뀌지 않는 부분 분리.
변화하는 부분을 뽑아내서 별도의 클래스 집합으로 분리!
public static void main(String[] args) {
new Step5().simulate();
}
public void simulate() {
Duck mallard = new MallardDuck();
mallard.performQuack();
mallard.performFly();
}
abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {}
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("모든 오리는 물에 뜹니다. 가짜 오리도 뜨죠.");
}
}
interface FlyBehavior {
public void fly();
}
class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("날고 있어요!~");
}
}
class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("저는 못 날아요");
}
}
interface QuackBehavior {
public void quack();
}
class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("꽥");
}
}
class MuteQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("<< 조용~ >>");
}
}
class Squeak implements QuackBehavior {
@Override
public void quack() {
System.out.println("삑");
}
}
class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("저는 물오리입니다");
}
}
Step 6. 전략 패턴 적용! 동적으로 행동 지정 가능하게 하기
세터 메소드로 오리의 행동을 동적으로 바꿀 수 있도록 함.
이제 중간에 오리의 행동 변경 가능.
☆ 물론 동적으로 변경 가능하다는 점이 유효한지는 프로젝트마다 달라질 것이라 생각됨. 항상 좋은건 절대 아님.
public static void main(String[] args) {
new Step6().simulate();
}
public void simulate() {
Duck mallard = new MallardDuck();
mallard.performQuack();
mallard.performFly();
Duck model = new ModelDuck();
model.performFly();
model.setFlyBehavior(new FlyRocketPowered());
model.performFly();
}
abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {}
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("모든 오리는 물에 뜹니다. 가짜 오리도 뜨죠.");
}
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
}
interface FlyBehavior {
public void fly();
}
class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("날고 있어요!~");
}
}
class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("저는 못 날아요");
}
}
class FlyRocketPowered implements FlyBehavior {
@Override
public void fly() {
System.out.println("로켓 추진으로 날아갑니다!");
}
}
interface QuackBehavior {
public void quack();
}
class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("꽥");
}
}
class MuteQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("<< 조용~ >>");
}
}
class Squeak implements QuackBehavior {
@Override
public void quack() {
System.out.println("삑");
}
}
class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("저는 물오리입니다");
}
}
class ModelDuck extends Duck {
public ModelDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
@Override
public void display() {
System.out.println("저는 모형 오리입니다");
}
}
전략 패턴?
- 알고리즘군을 정의하고 캡슐화해서 각각의 알고리즘군을 수정해서 쓸 수 있게 해준다.
- 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있음!
- 즉, 객체가 할 수 있는 알고리즘(행위) 각각의 전략 클래스들을 만들어서 갈아끼울 수 있게 해줌.
최종 코드 : github
'CS > Design Pattern' 카테고리의 다른 글
[디자인 패턴] 프록시 패턴 (Proxy Pattern) (0) | 2023.06.18 |
---|---|
자바 싱글톤 패턴의 변화 (다양한 싱글톤 패턴 구현 방법) (0) | 2022.11.15 |
댓글