open:strategy-pattern

Strategy Pattern

스벤 토리(Sven Tori)는 사용자 목록을 담은 페이지를 보는 데 많은 돈을 쓴다. 그런데 사용자는 이름순으로 정렬되어 있어야 하고, 유료 사용자들은 다른 사용자들보다 앞에 나타나야 한다. 그 이유는 돈을 지불하기 때문이다. 역순으로 정렬할 때에도 유료 사용자들은 앞에 나열되어야 한다.

페드로: 아! 커스텀 비교자(custom comparator)를 제공해서 Collectoins.sort(user, comparator)를 호출하면 되겠네요.

이브: 커스텀 비교자는 어떻게 구현하시려고요?

페드로: Comparator 인터페이스를 이용해 compare(Object o1, Object o2) 메소드를 구현하면 되요. ReverseComparator 클래스의 경우에도 마찬가지로 Comparator 인터페이스를 구현하면 됩니다.

이브: 말보다는 코드로 보여 주세요!

class SubsComparator implements Comparator<User> {

  @Override
  public int compare(User u1, User u2) {
    if (u1.isSubscription() == u2.isSubscription()) {
      return u1.getName().compareTo(u2.getName());
    } else if (u1.isSubscription()) {
      return -1;
    } else {
      return 1;
    }
  }
}

class ReverseSubsComparator implements Comparator<User> {

  @Override
  public int compare(User u1, User u2) {
    if (u1.isSubscription() == u2.isSubscription()) {
      return u2.getName().compareTo(u1.getName());
    } else if (u1.isSubscription()) {
      return -1;
    } else {
      return 1;
    }
  }
}

Collections.sort(users, new SubsComparator());

Collections.sort(users, new ReverseSubsComparator());

페드로: 클로저로는 어떻게 할 수 있죠?

이브: 예, 다음과 같이 합니다.

(sort (comparator
       (fn [u1 u2]
         (cond
           (= (:subscription u1)
              (:subscription u2)) (neg? (compare (:name u1)
                                                 (:name u2)))
           (:subscription u1) true
           :else false))) users)

페드로: 아주 유사하네요

이브: 하지만 더 간단하게 할 수도 있어요

;; forward sort
(sort-by (juxt (complement :subscription) :name) users)

;; reverse sort
(sort-by (juxt :subscription :name) #(compare %2 %1) users)

페드로: 세상에! 달랑 한 줄짜리 코드네요

이브: 보시다시피, 그냥 함수들일 뿐이죠

페드로: 어쨋거나, 코드를 이해하기는 매우 어렵네요.

이브는 juxtcomplement, sort-by 함수에 대해 설명한다.

10분이 흐른 뒤에

페드로: 전략 패턴 자체를 넘어서는 아주 이상한 방식이네요

이브: 상관 없어요. 전략 패턴은 단순히 어떤 함수에 인수로 전달되는 함수일 뿐이니까요.

(def users [{:name "Bob", :subscription :premium}
            {:name "Alice", :subscription nil}
            {:name "Eve", :subscription :premium}
            {:name "Carol", :subscription nil}
            {:name "Dave", :subscription :premium}
            {:name "Frank", :subscription nil}])

(sort-by (juxt (complement :subscription) :name) users)

;=> ({:name "Bob", :subscription :premium} {:name "Dave", :subscription :premium} {:name "Eve", :subscription :premium} {:name "Alice", :subscription nil} {:name "Carol", :subscription nil} {:name "Frank", :subscription nil})


  • open/strategy-pattern.txt
  • 마지막으로 수정됨: 2021/11/21 07:55
  • 저자 127.0.0.1