Java Enum을 사용한 전략 디자인 패턴

전략은 소프트웨어가 런타임 동안 알고리즘 제품군에서 하나를 선택할 수 있도록 하는 디자인 패턴입니다. 각 알고리즘은 자체 클래스에서 구현되어 클라이언트를 상호 교환할 수 있습니다. 전략 디자인 패턴을 사용하여 클래스는 다른 구현으로 동일한 메소드를 다른 방식으로 실행할 수 있습니다. 책Design Patterns by Gamma et al에 나오는 패턴 중 하나입니다.

예를 들어 통근해야 하는 직원을 생각해 보십시오. 그는 자동차, 오토바이, 자전거 또는 지하철과 같은 다양한 전략을 사용할 수 있습니다. 클래스worker에는 필드transport가 있습니다. 그리고 transport 에는 commute 메서드가 있습니다. 알고리즘이 있는 클래스는 Car , Motorcycle , BicycleMetro 입니다. Transport 인터페이스를 구현해야 합니다.

메서드 호출worker.transport.commute은 다른 알고리즘, 즉 다른 전략을 사용할 수 있습니다. 컨텍스트는 적절한 알고리즘을 선택할 책임이 없습니다. 이것은 하나의 전략을 선택하는 클라이언트에 의해 수행됩니다. 컨텍스트는 하나의 전략에서 메서드를 실행합니다. 따라서 컨텍스트는 구현과 무관합니다.

이 기사에서는 Java 열거형으로 전략 디자인 패턴을 구현합니다. 열거형에는 대부분의 프로그래머가 알고 있는 것보다 더 많은 기능이 있습니다.

이 접근 방식이 Open-Closed principle을 조금 위반하면 이에 대한 비판도 있습니다. 열거형을 사용하면 런타임에 새 구현을 추가할 수 없습니다. 코드를 업데이트해야 합니다. 코드를 봅시다.

검증인 전략



첫 번째 예는 XML, JSON, YAML 또는 CSV 콘텐츠에 대한 파일 형식 유효성 검사기입니다. 기존 전략 구현에서는 각 알고리즘에 대해 하나씩 여러 클래스가 필요합니다. 열거형을 사용하면 각 상수에서 비즈니스 규칙을 구현할 수 있습니다.

public enum ValidatorStrategy {

    XML {
        @Override
        void doValidation(String content) {
            // The validation code goes here
            System.out.println("This is a XML content");
        }
    },
    JSON {
        @Override
        void doValidation(String content) {
            // The validation code goes here
            System.out.println("This is a JSON content");
        }
    },
    YAML {
        @Override
        void doValidation(String content) {
            // The validation code goes here
            System.out.println("This is a YAML content");
        }
    },
    CSV {
        @Override
        void doValidation(String content) {
            // The validation code goes here
            System.out.println("This is a CSV content");
        }
    };

    abstract void doValidation(String content);

}


컨텍스트 클래스는 클라이언트로부터 전략을 수신하고 선택한 전략에서 알고리즘을 실행합니다.

public class ValidatorContext {

    private ValidatorStrategy strategy;

    public ValidatorContext(ValidatorStrategy strategy) {
        this.strategy = strategy;
    }

    public void setValidator(ValidatorStrategy validator) {
        this.strategy = validator;
    }

    public void runValidation(String content) {
        strategy.doValidation(content);
    }

}


마지막 구성 요소는 유효성 검사 전략을 컨텍스트에 전달하는 클라이언트입니다. 전략을 설정한 후에는 항상 메소드validator.runValidation를 호출하는지 확인하십시오.

ValidatorContext validator = new ValidatorContext(ValidatorStrategy.XML);
validator.runValidation("XML content");

validator.setValidator(ValidatorStrategy.YAML);
validator.runValidation("YAML content");

validator.setValidator(ValidatorStrategy.JSON);
validator.runValidation("JSON content");


날짜 포맷터 전략



이것은 전략 디자인 패턴의 또 다른 예입니다. 이제 컨텍스트 클래스가 구현을 전략 클래스로 전달하는 더 복잡한 상황이 있습니다. 이런 식으로 Spring 과 같은 종속성 주입 엔진을 사용할 수 있습니다.

public enum DateFormatterStrategy {
    BRAZIL {
        @Override
        public String doFormat(DateFormatterImpl formatter, Date date) {
            return formatter.formatBrazil(date);
        }
    },
    BELGIUM {
        @Override
        public String doFormat(DateFormatterImpl formatter, Date date) {
            return formatter.formatBelgium(date);
        }
    },
    US {
        @Override
        public String doFormat(DateFormatterImpl formatter, Date date) {
            return formatter.formatUS(date);
        }
    };

    public abstract String doFormat(DateFormatterImpl formatter, Date date);

}


구현 클래스는 아래와 같습니다. 여기에는 각 국가의 날짜 형식을 지정하는 비즈니스 규칙이 포함되어 있습니다.

public class DateFormatterImpl {

    private SimpleDateFormat sdfBrasil = new SimpleDateFormat("dd/MM/yyyy");
    private SimpleDateFormat sdfBelgium = new SimpleDateFormat("dd.MM.yyyy");
    private SimpleDateFormat sdfUS = new SimpleDateFormat("MM/dd/yyyy");

    public String formatBrazil(Date date) {
        return this.sdfBrasil.format(date);
    }

    public String formatBelgium(Date date) {
        return this.sdfBelgium.format(date);
    }

    public String formatUS(Date date) {
        return this.sdfUS.format(date);
    }

}


컨텍스트 클래스는 이전에 본 것과 매우 동일합니다. 즉, 눈에 띄는 차이가 없습니다.

public class DateFormatterContext {

    private DateFormatterStrategy strategy;
    private DateFormatterImpl formatter = new DateFormatterImpl();

    public DateFormatterContext(DateFormatterStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(DateFormatterStrategy strategy) {
        this.strategy = strategy;
    }

    public String format(Date date) {
        return this.strategy.doFormat(formatter, date);
    }

}


그리고 마지막 클라이언트 클래스는 이전 클래스와 매우 유사합니다. 전략을 설정한 후 메소드formatter.format를 실행하면 선택한 전략이 올바른 알고리즘을 수행합니다.

Date date = new Date();
DateFormatterContext formatter = new DateFormatterContext(DateFormatterStrategy.BELGIUM);
System.out.println("Belgium: " + formatter.format(date));

formatter.setStrategy(DateFormatterStrategy.BRAZIL);
System.out.println("Brazil: " + formatter.format(date));

formatter.setStrategy(DateFormatterStrategy.US);
System.out.println("US: " + formatter.format(date));


결론



Java Enum은 다양한 요구 사항에서 프로그래머를 도울 수 있는 고급 기능을 갖춘 편리한 특수 유형입니다. 이 경우 우리는 그들과 함께 전략 디자인 패턴을 구현했습니다. 이 접근 방식에는 단순성과 적은 수의 클래스와 같은 장점이 있습니다. 하지만 단점도 있고, 가장 눈에 띄는 것은 Open-Closed 원칙을 조금 깨는 것입니다.

이 게시물은 원래 Strategy Design Pattern with Java Enum에 게시되었습니다.

참고문헌



https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

좋은 웹페이지 즐겨찾기