자바 8의 전략 디자인 패턴

1. 소개

이 기사에서는 Java 8에서 전략 설계 패턴을 구현하는 방법을 살펴 보겠습니다.

먼저 패턴에 대한 개요를 제공하고 이전 버전의 Java에서 전통적으로 구현 된 방법을 설명합니다.

다음으로, 이번에는 Java 8 람다를 사용하여 패턴을 다시 시도하여 코드의 상세도를 줄입니다.

2. 전략 패턴

기본적으로 전략 패턴을 사용하면 런타임에 알고리즘의 동작을 변경할 수 있습니다.

일반적으로 알고리즘을 적용하는 데 사용되는 인터페이스로 시작한 다음 가능한 각 알고리즘에 대해 여러 번 구현합니다.

크리스마스, 부활절 또는 새해에 따라 구매에 다양한 유형의 할인을 적용해야한다고 가정 해 보겠습니다. 먼저 각 전략에 따라 구현 될 Discounter 인터페이스를 만들어 보겠습니다 .

public interface Discounter { BigDecimal applyDiscount(BigDecimal amount); } 

그런 다음 부활절에 50 % 할인을 적용하고 크리스마스에 10 % 할인을 적용한다고 가정 해 보겠습니다. 이러한 각 전략에 대한 인터페이스를 구현해 보겠습니다.

public static class EasterDiscounter implements Discounter { @Override public BigDecimal applyDiscount(final BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.5)); } } public static class ChristmasDiscounter implements Discounter { @Override public BigDecimal applyDiscount(final BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.9)); } } 

마지막으로 테스트에서 전략을 시도해 보겠습니다.

Discounter easterDiscounter = new EasterDiscounter(); BigDecimal discountedValue = easterDiscounter .applyDiscount(BigDecimal.valueOf(100)); assertThat(discountedValue) .isEqualByComparingTo(BigDecimal.valueOf(50));

이것은 꽤 잘 작동하지만 문제는 각 전략에 대해 구체적인 클래스를 만들어야하는 것이 약간 고통 스러울 수 있다는 것입니다. 대안은 익명 내부 유형을 사용하는 것이지만 여전히 이전 솔루션보다 훨씬 장황하고 편리하지 않습니다.

Discounter easterDiscounter = new Discounter() { @Override public BigDecimal applyDiscount(final BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.5)); } }; 

3. Java 8 활용

Java 8이 출시 된 이후로 람다의 도입으로 익명의 내부 유형이 다소 중복되었습니다. 즉, 전략 수립이 이제 훨씬 더 깔끔하고 쉬워졌습니다.

또한 함수형 프로그래밍의 선언적 스타일을 통해 이전에는 불가능했던 패턴을 구현할 수 있습니다.

3.1. 코드 상세도 줄이기

이번에는 람다 식을 사용하여 인라인 EasterDiscounter를 만들어 보겠습니다 .

Discounter easterDiscounter = amount -> amount.multiply(BigDecimal.valueOf(0.5)); 

보시다시피, 우리의 코드는 이제 훨씬 깨끗하고 유지 관리가 쉬워 이전과 동일하지만 한 줄로 달성됩니다. 기본적 으로 람다는 익명의 내부 유형을 대체하는 것으로 볼 수 있습니다 .

이 이점은 더 많은 Discounters 를 라인 에 선언 할 때 더욱 분명해집니다 .

List discounters = newArrayList( amount -> amount.multiply(BigDecimal.valueOf(0.9)), amount -> amount.multiply(BigDecimal.valueOf(0.8)), amount -> amount.multiply(BigDecimal.valueOf(0.5)) );

많은 할인 기를 정의하고 싶을 때 모두 한곳에서 정적으로 선언 할 수 있습니다. Java 8에서는 원하는 경우 인터페이스에서 정적 메서드를 정의 할 수도 있습니다.

따라서 구체적인 클래스 또는 익명 내부 유형 중에서 선택하는 대신 단일 클래스에서 람다를 모두 만들어 보겠습니다.

public interface Discounter { BigDecimal applyDiscount(BigDecimal amount); static Discounter christmasDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf(0.9)); } static Discounter newYearDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf(0.8)); } static Discounter easterDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf(0.5)); } } 

보시다시피, 우리는 그리 많지 않은 코드로 많은 것을 성취하고 있습니다.

3.2. 활용 기능 구성

Discounter 인터페이스를 수정 하여 UnaryOperator 인터페이스를 확장 한 다음 combine () 메서드 를 추가해 보겠습니다 .

public interface Discounter extends UnaryOperator { default Discounter combine(Discounter after) { return value -> after.apply(this.apply(value)); } }

기본적으로, 우리는 우리의 리팩토링하는 자동 할인을 하고 할인을 적용하는 것은 변환 함수는 사실 활용 의 BigDecimal 다른에 인스턴스 의 BigDecimal, 액세스 미리 정의 된 방법으로 우리를 수를 . 는 AS UnaryOperator가 되어 적용 () 방법, 우리는 단지 대체 할 수 applyDiscount을 함께.

결합 () 메소드는 하나인가 주변 단지 추상화 할인기를 결과로 이. 이를 위해 내장 함수 apply () 를 사용합니다.

이제 여러 할인 기를 한 금액에 누적 적용 해 보겠습니다 . 함수 reduce ()combine () 을 사용하여이를 수행합니다 .

Discounter combinedDiscounter = discounters .stream() .reduce(v -> v, Discounter::combine); combinedDiscounter.apply(...);

첫 번째 축소 인수에 특히주의하십시오 . 할인이 제공되지 않으면 변경되지 않은 값을 반환해야합니다. 이는 기본 할인기로 ID 기능을 제공하여 달성 할 수 있습니다.

이것은 표준 반복을 수행하는 것보다 유용하고 덜 장황한 대안입니다. 기능 구성을 위해 상자에서 꺼내는 방법을 고려하면 훨씬 더 많은 기능을 무료로 제공합니다.

4. 결론

이 기사에서는 전략 패턴을 설명하고 람다 식을 사용하여 덜 장황한 방식으로 구현하는 방법을 보여주었습니다.

이러한 예제의 구현은 GitHub에서 찾을 수 있습니다. 이것은 Maven 기반 프로젝트이므로 그대로 실행하기 쉽습니다.