금백조의 개발 블로그

[디자인 패턴]전략 패턴(Strategy Pattern) 실사용 사례 본문

디자인 패턴(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 원칙에 부합한다.

참고

https://hudi.blog/strategy-pattern/

반응형