Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

스트래티지 패턴 #137

Open
psi1104 opened this issue Oct 31, 2021 · 0 comments
Open

스트래티지 패턴 #137

psi1104 opened this issue Oct 31, 2021 · 0 comments

Comments

@psi1104
Copy link
Collaborator

psi1104 commented Oct 31, 2021

Strategy Pattern

Strategy Pattern은 객체들의 행위를 클래스로 만들어서 캡슐화한 뒤, 행위의 변경이나 수정이 필요할 때 동적으로 행위를 바꿀 수 있도록 하는 디자인 패턴입니다.

Strategy Pattern 사용 예

public abstract class Robot {
  private String name;
  public Robot(String name) { this.name = name; }
  public String getName() { return name; }
  // 추상 메서드
  public abstract void attack();
  public abstract void move();
}

public class TaekwonV extends Robot {
  public TaekwonV(String name) { super(name); }
  public void attack() { System.out.println("I have Missile."); }
  public void move() { System.out.println("I can only walk."); }
}
public class Atom extends Robot {
  public Atom(String name) { super(name); }
  public void attack() { System.out.println("I have strong punch."); }
  public void move() { System.out.println("I can fly."); }
}
public class Client {
  public static void main(String[] args) {
    Robot taekwonV = new TaekwonV("TaekwonV");
    Robot atom = new Atom("Atom");

    System.out.println("My name is " + taekwonV.getName());
    taekwonV.move();
    taekwonV.attack();

    System.out.println()
    System.out.println("My name is " + atom.getName());
    atom.move();
    atom.attack();
  }
}

Atom이 움직이는 방법을 수정한다면?

public class Atom extends Robot {
  public Atom(String name) { super(name); }
  public void attack() { System.out.println("I have strong punch."); }

  //public void move() { System.out.println("I can fly."); }
  public void move() { System.out.println("I can only walk."); } // 수정
}
  • move()를 수정하려면 기존 코드의 내용을 수정해야 하므로 OCP에 위배됩니다.

  • 상속을 통한 메소드 overriding 구현은 중복 코드가 발생하기 쉽습니다.

    • TaekwonV와 Atom의 move() 메서드 내용이 중복됩니다.

    • 새로운 방식으로 수정하려면 중복 코드를 모두 수정해야 합니다.

해결 방법

  • 변화되는 것을 찾고 이를 클래스로 캡슐화합니다.
    • 변화되는 것: attact(), move()
    • 공격과 이동을 위한 인터페이스를 만들고 이들을 구현한 클래스를 만들어서 캡슐화.
  • strategy 멤버 변수를 추가하고 setter로 넣어줍니다.
    • 공격과 이동을 상속받는 것이 아니라 외부 타입의 멤버 변수로 만든다.
    • 상속이 아닌 구성으로 setter를 통해 동적으로 바인딩이 가능하다.
    • Robot에 새로운 공격과 이동 방법을 추가할 때 Robot 구현 클래스를 수정하지 않아도 된다.
    • OCP를 만족
public abstract class Robot {
private String name;
private AttackStrategy attackStrategy;
private MovingStrategy movingStrategy;

public Robot(String name) { this.name = name; }
public String getName() { return name; }
public void attack() { attackStrategy.attack(); }
public void move() { movingStrategy.move(); }

// setter 메서드
public void setAttackStrategy(AttackStrategy attackStrategy) {
  this.attackStrategy = attackStrategy; }
public void setMovingStrategy(MovingStrategy movingStrategy) {
  this.movingStrategy = movingStrategy; }
}
public class TaekwonV extends Robot {
	public TaekwonV(String name) { super(name); }
}

public class Atom extends Robot {
	public Atom(String name) { super(name); }
}
// 인터페이스
interface AttackStrategy { public void attack(); }

// 구체적인 클래스
public class MissileStrategy implements AttackStrategy {
  public void attack() { System.out.println("I have Missile."); }
}

public class PunchStrategy implements AttackStrategy {
  public void attack() { System.out.println("I have strong punch."); }
}
// 인터페이스
interface MovingStrategy { public void move(); }

// 구체적인 클래스
public class FlyingStrategy implements MovingStrategy {
  public void move() { System.out.println("I can fly."); }
}

public class WalkingStrategy implements MovingStrategy {
  public void move() { System.out.println("I can only walk."); }
}
public class Client {
	public static void main(String[] args) {
      Robot taekwonV = new TaekwonV("TaekwonV");
      Robot atom = new Atom("Atom");

      /* 수정된 부분: 전략 변경 방법 */
      taekwonV.setMovingStrategy(new WalkingStrategy());
      taekwonV.setAttackStrategy(new MissileStrategy());
      atom.setMovingStrategy(new FlyingStrategy());
      atom.setAttackStrategy(new PunchStrategy());

      /* 아래부터는 동일 */
      System.out.println("My name is " + taekwonV.getName());
      taekwonV.move();
      taekwonV.attack();

      System.out.println()
      System.out.println("My name is " + atom.getName());
      atom.move();
      atom.attack();
	}
}

장점 및 단점

  • 장점
    • 동적으로 Context 의 행위를 변경할 수 있습니다.
    • Context 코드의 변경 없이 새로운 Strategy를 추가하여 수정할 수 있습니다.
      • OCP를 만족합니다.
  • 단점
    • Strategy 객체와 Context 객체 사이에 통신 오버헤드가 생깁니다.
      • Context 객채는 사용하지 않는 Strategy 정보도 갖게 됩니다.
    • 객체 수가 증가합니다.

실제 사용 예시

Spring framework 에서 oauth2 를 이용하여 google, facebook, 등 로그인을 사용하는 예제

스프링 부트 어플리케이션의 전략 패턴

Reference

https://gmlwjd9405.github.io/2018/07/06/strategy-pattern.html

https://victorydntmd.tistory.com/292

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant