JAVA

디자인 패턴 - 전략 패턴

승운노트 2025. 10. 2. 14:04
 

스프링 부트 포트폴리오 활용 사례

전략 패턴은 스프링의 의존성 주입(DI)과 결합될 때 매우 강력한 시너지를 냅니다.

사례 1: 사용자 등급별 할인 정책

쇼핑몰에서 사용자 등급(BRONZE, SILVER, GOLD)에 따라 할인율이나 포인트 적립률을 다르게 적용해야 할 때 사용할 수 있습니다.

  • 컨텍스트: OrderService
  • 전략 인터페이스: DiscountPolicy
  • 구현체: BronzeDiscountPolicy, SilverDiscountPolicy, GoldDiscountPolicy

OrderService는 주문을 처리할 때, 사용자의 등급에 맞는 DiscountPolicy 구현체를 주입받아 할인 금액을 계산합니다. 새로운 'VIP' 등급이 생겨도 VipDiscountPolicy만 추가하면 되므로 OrderService는 변경되지 않습니다.

사례 2: 파일 업로드 처리

사용자가 업로드한 파일을 어디에 저장할지 동적으로 결정해야 할 때 유용합니다.

  • 컨텍스트: FileUploadService
  • 전략 인터페이스: StorageStrategy
  • 구현체: LocalFileStorageStrategy (서버 로컬 디스크에 저장), AwsS3StorageStrategy (AWS S3에 저장), DatabaseStorageStrategy (DB에 BLOB으로 저장)

FileUploadService는 파일의 종류, 크기, 또는 시스템 환경설정 값에 따라 적절한 StorageStrategy를 선택하여 파일 저장을 위임합니다.

사례 3: 데이터 검증(Validation) 규칙

입력 데이터에 대해 여러 단계의 복잡한 검증 규칙을 적용해야 할 때, 각 검증 규칙을 하나의 전략으로 만들 수 있습니다.

  • 컨텍스트: UserRegistrationService
  • 전략 인터페이스: ValidationStrategy
  • 구현체: PasswordStrengthValidation, EmailFormatValidation, DuplicateUsernameValidation

 

package ch03;

import java.util.Base64;

/**
 * 전략 패턴이 없는 코드를 사용해 보자.
 * 문제 : 텍스트를 인코딩하는 방식이 여러가지 일 때, 우리는 Encoder 클래스를 설계 해 볼 수 있다.
 */

/**
 * OCP
 * 기능에 확장에 있어서는 열려 있어야 한다.
 * 기존 코드에 수정은 닫혀 있어야 한다.
 * 새로운 인코딩 형태가 추가 된다면 매번 if else 구문을 직접 수정해야 된다.
 */

class Encoder {

    public String encode(String text, String format) {
        if ("base64".equalsIgnoreCase(format)) {
            return Base64.getEncoder().encodeToString(text.getBytes());
        } else if ("append".equalsIgnoreCase(format)) {
            return "ABC:" + text;
        } else {
            return text;
        }
    }
}


// 클라이언트 클래스
public class BadEncode {

    // 코드의 진입점
    public static void main(String[] args) {

        Encoder encoder = new Encoder();
        String message = "Hello Java";

        System.out.println(encoder.encode(message, "base64"));
        System.out.println(encoder.encode(message, "append"));
    }

}

 

 

 

package ch03.step01;

/**
 * 전략 패턴이란?
 * 동작 방식을 캡슐화하여
 * 동적으로 전략을 변경할 수 있도록 허용하는 디자인 패턴
 * 특정 기능을 수행할 여러 방법이 있을 때, 그 방법들을 정의(클래스)하고
 * 필요에 따라서 적절한 전략을 선택해서 사용할 수 있습니다.
 */


public interface EncodingStrategy {
    String encode(String text);

}

 

 

package ch03.step01;

public class AppendStrategy  implements EncodingStrategy {
    @Override
    public String encode(String text) {
        return "ABC:" + text;
    }
}

 

 

package ch03.step01;

import java.util.Base64;

public class Base64Strategy implements EncodingStrategy{
    @Override
    public String encode(String text) {
        return Base64.getEncoder().encodeToString(text.getBytes());
    }
}

 

 

package ch03.step01;


/**
 * 핵심 코드 - 전략을 사용하는 주체
 */
public class Encoder {

    // 인터페이스 타입의 전략을(인코딩 형태 클래스) 필드로 가짐
    private EncodingStrategy encodingStrategy;

    // 전략을 동적으로 교체 하는 메서드
    public void setEncodingStrategy(EncodingStrategy encodingStrategy) {
        this.encodingStrategy = encodingStrategy;
    }
    public String getMessage(String message) {
        return encodingStrategy.encode(message);
    }

}

 

 

package ch03.step01;

public class MainTest {

    public static void main(String[] args) {

        String message = "hello java";
        // 요청에 따라서 인코딩 하고 싶다.
        Encoder encoder = new Encoder();

        //Base64로 전략을 선택
        encoder.setEncodingStrategy(new Base64Strategy());
        System.out.println(encoder.getMessage(message));

        encoder.setEncodingStrategy(new AppendStrategy());
        System.out.println(encoder.getMessage(message));

        encoder.setEncodingStrategy(new UrlStrategy());
        System.out.println(encoder.getMessage(message));
    }

}

'JAVA' 카테고리의 다른 글

[1단계] 프로젝트 초기 설정과 핵심 도메인 설계  (0) 2025.10.15
프로젝트생성  (0) 2025.10.15
디자인 패턴 - 어댑터 패턴  (0) 2025.10.02
디자인 패턴 - 팩토리 패턴  (0) 2025.10.02
디자인 패턴 - 싱글톤  (0) 2025.09.30