프로그래밍 언어들 중에는 특정 함수를 호출할 수 있는 언어들이 있습니다.
C같은 경우에는 포인터를 이용해서, 대리자(delegate), 자바도 사용할 수 있는 람다 표현식이 있죠.
전략을 표현하는데에 포인터가 좋은 방법이 될 수 있지만
자바는 포인터를 지원하지 않습니다. 자바는 어떤 경우라도 주소값을 직접 건드리지 못하게 하죠.
하지만 비슷한 메소드를 사용할 수 있습니다.
함수 객체(function object)라고 하는 방법입니다.
public class StringLengthComparator {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}
이 코드는 문자열을 비교하여 차이를 계산해주는 전략을 가지고 있습니다.
단 하나의 메소드를 가지고 있으며, 무상태 클래스입니다.(필드가 없고 그 모든 객체는 기능적으로 동일한 클래스)
이런 메소드는 싱클톤으로 사용하는 것이 좋습니다.
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);
}
제네릭으로 만들어진 인터페이스입니다.
스트링 뿐만아니라 배열등도 사용이 가능할 수 있겠네요.
위의 코드는 이 인터페이스를 구현해서 만들어 둔다면
더 깔끔하고 객체지향에 맞는 코드가 될 수 있겠죠.
또한 실행 가능 전략 클래스는 익명클래스의 형식을 가질 수도 있습니다.
Arrays.sort(stringArray, new Comparator<String>() {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
하지만 익명클래스는 호출될 때마다 매번 객체를 새로 생성하기에
많이 사용된다면 정적변수르 저장해두고 재사용하는 것이 좋습니다.
이 코드는 람다로 바꾸면
Arrays.sort(stringArray, (String s1, String s2) -> {
return s1.length() - s2.length();
});
더 깔끔해지겠네요.
전략을 표현하는 방법 중에는 호스트 클래스도 있습니다.
전략 인터페이스는 실행 가능 전략 객체들의 자료형 구실을 하기에
굳이 public으로 만들어 공개하지 않아도 됩니다.
class Host {
private static class strLenCmp implements Comparator<String>, Serializable {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
public static final Comparable<String> STRING_LENGTH_COMPARATOR = new strLenCmp();
}
}
이런 식으로 호스트 클래스를 만들어
전략 클래스들을 모아놓고 쓰는 것도 하나의 방법이 될 수 있습니다.
'프로그래밍 > Java' 카테고리의 다른 글
이펙티브 자바 규칙 22 - 내부클래스 종류와 멤버 클래스는 가능하면 static으로 (0) | 2018.03.05 |
---|---|
이펙티브 자바 규칙 20 - 태그가 달린 클래스 대신 클래스 계층을 활용하라 (0) | 2018.02.20 |
이펙티브 자바 규칙 19 - 인터페이스는 자료형을 정의할 때만 사용하라 (0) | 2018.02.18 |