디자인 패턴(Design pattern)/전략 패턴(Strategy Pattern)
[디자인 패턴]전략 패턴(Strategy Pattern) 실사용 사례
금백조
2023. 9. 20. 20:54
반응형
서론
각 구현 클래스에서 Exception이 발생할 경우 로그를 생성하는 CreateLog 클래스가 존재했습니다.
로그가 생성될 때 구현 클래스의 종류에 따라 서비스 상태를 업데이트 해야하는 로직이 필요했습니다.
이를 위해 전략 패턴(Strategy Pattern)을 적용한 사례를 글로 써봅니다.
본론
상황
- 아래의 A,B,CService 클래스가 CreateLog클래스를 참조하여 로그를 생성하고 있다.
요구사항
- CreateLog 클래스에서 각 서비스의 상태를 업데이트해야 하는 로직을 구현해야한다.
public class AService {
public void doSomeThing(){
//AService 구현 로직...
try{
} catch (Exception e){
new CreateLog().doCreateLog();
}
}
}
public class BService {
public void doSomeThing(){
//BService 구현 로직...
try{
} catch (Exception e){
new CreateLog().doCreateLog();
}
}
}
public class CService {
public void doSomeThing(){
//CService 구현 로직...
try{
} catch (Exception e){
new CreateLog().doCreateLog();
}
}
}
public class CreateLog(){
public void doCreateLog(){
//로그 생성 로직...
}
}
전략 패턴을 사용하지 않는다면?
- 구현 클래스의 종류를 파악하기 위해 구분하는 파라미터를 전달해야 하고 if else 문으로 분기처리를 해야한다. 이를 클래스 다이어그램, 구현 코드로 보면 아래와 같다.
클래스 다이어그램
구현 코드
public class AService {
public void doSomeThing(){
//AService 구현 로직...
try{
} catch (Exception e){
new CreateLog("AService").doCreateLog();
}
}
}
public class BService {
public void doSomeThing(){
//BService 구현 로직...
try{
} catch (Exception e){
new CreateLog("BService").doCreateLog();
}
}
}
public class CService {
public void doSomeThing(){
//CService 구현 로직...
try{
} catch (Exception e){
new CreateLog("CService").doCreateLog();
}
}
}
public class CreateLog(){
private String serviceName;
public CreateLog(){
}
public CreateLog(String serviceName){
this.serviceName= serviceName;
}
public void doCreateLog(){
//로그 생성 로직...
//테이블 상태 업데이트
if(serviceName == "AService"){
AServiceUpdateStatus();
} else if(serviceName == "BService"){
BServiceUpdateStatus();
} else if(serviceName == "CService"){
CServiceUpdateStatus();
}
}
public void AServiceUpdateStatus(){
System.out.println("A서비스 상태 업데이트");
}
public void BServiceUpdateStatus(){
System.out.println("B서비스 상태 업데이트");
}
public void CServiceUpdateStatus(){
System.out.println("C서비스 상태 업데이트");
}
}
단점
- 새로운 서비스가 추가될 때 마다 if else 분기처리 로직에 추가를 해줘야한다. 즉 서비스가 추가될 때 마다 CreateLog클래스도 수정을 해야한다. 이는 객체 지향 설계 5원칙(SOLID) 중 확장에 유연하고 수정을 최소화하는 개방 폐쇄 원칙(OCP)에 위배된다.
전략 패턴(Strategy Pattern) 적용
- 각 서비스에 상태를 업데이트해야 하는 로직을 하나의 전략 인터페이스로 추상화하고 전략 객체를 구현한다. CreateLog 클래스에 각 서비스마다 호출해야할 전략 객체들을 주입한다. 이를 클래스 다이어그램, 구현 코드로 보면 아래와 같다.
클래스 다이어그램
구현 코드
전략 추상화 인터페이스 생성
public interface UpdateStatusStrategy {
void doUpdateStatus();
}
전략 객체 구현
public class AServiceUpdateStatusStrategy implements UpdateStatusStrategy {
@Override
void doUpdateStatus(){
System.out.println("A서비스 상태 업데이트");
}
}
public class BServiceUpdateStatusStrategy implements UpdateStatusStrategy {
@Override
void doUpdateStatus(){
System.out.println("B서비스 상태 업데이트");
}
}
public class CServiceUpdateStatusStrategy implements UpdateStatusStrategy {
@Override
void doUpdateStatus(){
System.out.println("C서비스 상태 업데이트");
}
}
전략 객체 주입
public class AService {
public void doSomeThing(){
//AService 구현 로직...
try{
} catch (Exception e){
new CreateLog(new AServiceUpdateStatusStrategy()).doCreateLog();//전략 주입
}
}
}
public class BService {
public void doSomeThing(){
//BService 구현 로직...
try{
} catch (Exception e){
new CreateLog(new BServiceUpdateStatusStrategy()).doCreateLog();//전략 주입
}
}
}
public class CService {
public void doSomeThing(){
//CService 구현 로직...
try{
} catch (Exception e){
new CreateLog(new CServiceUpdateStatusStrategy()).doCreateLog();//전략 주입
}
}
}
public class CreateLog(){
private UpdateStatusStrategy updateStatusStrategy;
public CreateLog(){
}
public CreateLog(UpdateStatusStrategy updateStatusStrategy){
this.updateStatusStrategy= updateStatusStrategy;
}
public void doCreateLog(){
//로그 생성 로직...
//테이블 상태 업데이트
if(updateStatusStrategy != null){
doUpdateStatus();
}
}
private void doUpdateStatus(){
updateStatusStrategy.doUpdateStatus();//전략 실행
}
}
장점
- 새로운 서비스가 추가되어도 전략 객체를 구현하고 주입만 하면 되므로 CreateLog 클래스는 수정하지 않아도 된다. 이는 OCP 원칙에 부합한다.
참고
반응형