# 설명 - 전략패턴 적용
정책이나 알고리즘을 교체하여 유연하게 사용 가능함
- if-else문과 같은 것이 없어질 수 있음
- 한 분야(행동)에 대한 다양한 알고리즘이 존재하면, 이 알고리즘을 캡슐화하여 사용 할 수 있음
- 시스템이 커질경우 메서드 중복문제를 해결함
- OCP(Open-Close-Principle)에 위배되지 않게 함. 확장에는 열려있어야하며 수정에는 닫혀있어야함
## 예제
- 전화 상담을 하는 상담원이 존재한다고 가정하자.
- 이 상담원들에게는 3가지의 근무 방식(스케줄링)이 존재한다. RoundRobin, LeastJob, Priority 방식으로 다음 상담자를 배분할 수 있다.
Scheduler이라는 Strategy(전략)을 정의하고, RoundRobin, LeasJob, Priority에 맞는 알고리즘(기능)을 구현한다.
Teller(상담원)에는 setScheduleType이라는 메서드를 통해서 근무방식(스케줄링)을 수정할 수 있는 기능이 있다. 만약 새로운 근무방식(스케줄링)이 도입된다고 하더라도 Scheduler를 implements하여 새로운 알고리즘(기능)을 추가하고, Teller에게 set해주면 된다.
상담원에게 새로운 업무(기능)이 추가되면 새로운 Strategy를 만들고 이를 implements하여 알고리즘(기능)을 추가시키고, set하여 사용하면 된다.
만약 이렇게 전략을 분리시키지 않고, Scheduler자체를 각각의 Teller에게 구현하면 어떤 문제점이 발생하는지 그 다음 예제에서 살펴보자.
# 코드 - 전략패턴 적용
## Scheduler
// Scheduler
// 전화 받는 스케줄링 방법에 대한 전략
public interface Scheduler {
public void getNextCall();
public void sendCallToAgent();
}
// RoundRobin
public class RoundRobin implements Scheduler{
@Override
public void getNextCall() {
System.out.println("RoundRobin 방식으로 다음 상담원을 연결합니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("------연결중------");
System.out.println("RoundRobin, 상담원 연결이 됐습니다");
System.out.println("------상담완료------");
}
@Override
public String toString() {
return "RoundRobin Scheduler";
}
}
// PriorityAllocation
public class PriorityAllocation implements Scheduler{
@Override
public void getNextCall() {
System.out.println("PriorityAllocation 방식으로 다음 상담원을 연결합니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("------연결중------");
System.out.println("PriorityAllocation, 상담원 연결이 완료 됐습니다");
System.out.println("------상담완료------");
}
@Override
public String toString() {
return "PriorityAllocation Scheduler";
}
}
// LeastJob
public class LeastJob implements Scheduler{
@Override
public void getNextCall() {
System.out.println("LeastJob 방식으로 다음 상담원을 연결합니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("------연결중------");
System.out.println("LeastJob, 상담원 연결이 됐습니다");
System.out.println("------상담완료------");
}
@Override
public String toString() {
return "LeastJob Scheduler";
}
}
## Teller
이 예제에서는 Teller를 굳이 abstract로 만드는 형태를 따를 필요는 없었지만 badsample을 설명하기 위해서 이렇게 했다.
public abstract class Teller {
public String name;
public Scheduler mScheduler;
public Teller(String name){
this.name = name;
mScheduler = null;
}
public void setScheduleType(Scheduler scheduleType) {
this.mScheduler = scheduleType;
System.out.println(mScheduler + " 방식으로 근무합니다.");
}
public void takeCall(){
mScheduler.getNextCall();
mScheduler.sendCallToAgent();
}
}
public class KoreaTeller extends Teller{
public KoreaTeller(String name) {
super(name);
}
}
# 테스트
// Test
public class Test {
public static void main(String[] args) {
// Strategy를 통해 구현된 알고리즘(행동)
Scheduler leastJob = new LeastJob();
Scheduler roundRobin = new RoundRobin();
Scheduler priority = new PriorityAllocation();
Teller hojun = new KoreaTeller("KoreaHojun");
// leastJob
hojun.setScheduleType(leastJob);
hojun.takeCall();
System.out.println();
// roundRobin
hojun.setScheduleType(roundRobin);
hojun.takeCall();
System.out.println();
// priority
hojun.setScheduleType(priority);
hojun.takeCall();
System.out.println();
}
}
근무 방식(스케줄링)을 set을 통해 유연하게 바꿀 수 있다. KoreanTeller 객체 자체를 수정하지 않아도 된다. 확장에 유연하고 수정에 폐쇄적인 OCP를 만족했다.
# 설명 - 전략패턴 미적용시
Scheduler이라는 기능을 RoundRobinTeller, PriorityTeller에 직접 구현 하도록 했다. 이럴 경우 시스템 확장시 유지보수를 어렵게 하며, RoundRobin에 대한 기능이 수정되야 할 경우, RoundRobinTeller를 수정해야하는 상황이 벌어져 OCP에 위배된다.
# 코드 - 전략패턴 미적용시
## Scheduler
public interface Scheduler {
public void getNextCall();
public void sendCallToAgent();
}
## Teller
public class RoundRobinTeller implements Scheduler {
public String name;
RoundRobinTeller(){
name = "RoundRobinTeller";
}
@Override
public void getNextCall() {
System.out.println("RoundRobin 방식으로 다음 상담원을 연결합니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("------연결중------");
System.out.println("RoundRobin, 상담원 연결이 됐습니다");
System.out.println("------상담완료------");
}
}
public class PriorityTeller implements Scheduler {
public String name;
PriorityTeller(){
name = "PriorityTeller";
}
@Override
public void getNextCall() {
System.out.println("PriorityAllocation 방식으로 다음 상담원을 연결합니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("------연결중------");
System.out.println("PriorityAllocation, 상담원 연결이 완료 됐습니다");
System.out.println("------상담완료------");
}
}
# 마치며
객체지향 공부하면서 디자인패턴을 알아가니까, OOP진짜 재밌는거 같다.
'• 독서 > Design Pattern' 카테고리의 다른 글
[디자인패턴] 데코레이터 패턴(Decorator Pattern) (0) | 2022.09.27 |
---|---|
[디자인패턴] 브릿지 패턴(Bridge Pattern) (0) | 2022.09.22 |
[디자인패턴-위임/팩토리패턴] 팩토리 메소드 패턴 (Factory-Method Pattern) (2) | 2022.09.20 |
[디자인패턴-위임패턴] 템플릿 메서드 패턴(Template Method) (0) | 2022.09.18 |
[디자인패턴-생성패턴] 빌더 패턴(Builder Pattern) (2) | 2022.09.17 |