Item 21. 전략을 표현하고 싶을 때는 함수 객체를 사용하라

전략패턴(Strategy Pattern)

  • 알고리즘군을 정의하고 각각을 캡슐화하여 교환해서 사용 스트래티지를 활용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경가능

  • Java에서 사용중인 전략패턴

    • java.util.Comparator#compare() called by Collections.sort()
    • javax.servlet,http.HttpServlet#service
    • javax.servlet.Filter#doFilter
  • Strategy Pattern vs Template Pattern

실행 가능 전략(concrete strategy)

  • 함수 객체(function object) 객체 참조를 통해 포인터와 비슷한 효과를 달성 가능. 객체의 메서드는 호출 대상 객체에 뭔가를 한다. 다른 객체에 작용하는 메서드 즉 인자로 전달된 객체에 뭔가를 하는 메서드를 정의하는 것도 가능하다. 가지고 있는 메서드가 그 메서드 하나 뿐인 객체는 해당 메서드의 포인터 구실을 한다.
// 문자열 비교하는데 사용 가능
class StringLegthComparator{
   public int compare(String s1,String s2) {
      return s1.length() - s2.length();
   }
  };
```

싱글턴 패턴(singleton pattern)을 따르면 쓸데없는 객체 생성은 피할수 있다

  • stateless class
public class StringLengthComparator {
    private StringLengthComparator() {}
    public static final StringLengthComparator INSTANCE
    = new StringLengthComparator();
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
}

다른 실행 가능 전략 클래스에 어울리는 전략 인터페이스 만들기

public interface Comparator<T> {
    public int compare(T t1, T t2);
}
public class StringLengthComparator implements Comparator<String> {  
    private StringLengthComparator() {}
    public static final StringLengthComparator INSTANCE
    = new StringLengthComparator();
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
}
  • 실행 가능 전략 클래스를 익명클래스로 정의하는 경우
Arrays.sort(StringArray, new Comparator<String>() {  
    public int compare(String t1, String t2) {
        return s1.length() - s2.length();
    }
});

ㄴ sort를 호출 할 때마다 새로운 객체 생성 , 여러번 수행되는 클래스라면 함수 객체를 private static final 필드에 저장하고 재사용 고려 => 함수 객체에 의도가 뚜렷한 이름을 붙일 수 있다는 장점도 있

  • 실행 가능 전략 객체들의 자료형 구실 public으로 만들 필요 없고 자료형인 public static 필드를 갖는 host class 를 정의 하는 것도 방법 호스트 클래스의 private 중첩 클래스로 정의하면 된다.
class Host{
    private static class StrLenCmp 
            implements Comparator<String>, Serializable{
        public int compare(String s1, String s2){
            return s1.length() - s2.length();
        }
    }

    public static final Comparator<String>
             STRING_LENGTH_COMPARATOR = new StrLenCmp();

    ... // 나머지 생략
}

ㄴ 실행가능 전략 클래스가 Serializable 인터페이스까지 구현해야 하므로 익명클래스 대신 static 멤버 클래스 사용

함수 객체의 주된 용도는 전략 패턴을 구현하는 것이다.

  • 전략을 표현하는 인터페이스를 선언하고, 실행 가능 전략 클래스가 전부 해당 인터페이스를 구현하도록 해야 한다.
  • 실행 가능 전략이 한 번만 사용되는 경우에는 보통 그 전략을 익명 클래스 객체로 구현한다.
  • 반복적으로 사용된다면 private static 멤버 클래스로 전략을 표현한 다음(내부 중첩 클래스), 전략 인터페이스가 자료형인 public static final 필드를 통해 외부에 공개하는 것이 바람직하다.

참조))

results matching ""

    No results matching ""