2013-04-15 3 views
2

일반적으로 비교기는 서로 다른 특성을 사용하여 개체를 비교하려는 경우에 가장 적합합니다 (How to compare objects by multiple fields 참조). 그러나 필자는 필자가 비교기 사용에 대해 확신하지 못한다.비교자를 사용하지 않고 다른 특성으로 개체 비교

문제는 다음과 같습니다. Node<S>이라는 일반 인터페이스를 정의했으며 다른 구성 요소는 입니다. 이 또한 Node<S>를 확장하는 CostNode<S>이며, CostNode<S> 확장하는 ScoreNode<S> :이 시점에서

public interface Node<S> { 
    S getS(); 
    // more methods... 
} 

public interface CostNode<S> extends Node<S> { 
    // This method smells really bad 
    int compareByCost(ComparableNode<S> node); 
} 

public interface ScoreNode<S> extends CostNode<S> { 
    // int compareByCost(CostNode<S> node) (from CostNode<S>) 
    int compareByScore(ScoreNode<S> node); 
} 

는, 누군가가 주장 할 수 있습니다, 당신은 다른 비교기를 사용하여 비교하는 당신은 CostNode 및 ScoreNode 필요하지 않습니다 노드. 괜찮아. 그러나 이제 "문제"가 발생합니다.

Client라는 구성 요소가 있으며 이는 ScoreNodes를 사용합니다. 클라이언트 생성 ScoreNodes의 책임이있는 사용자가 제공하는 노드 공장, 필요 당신이 볼 수 있듯이, 비교 노드의 동작은 노드에 포함되어

public class Client { 
    // ... 

    public Client(NodeFactory<S, ScoreNode<S>> nodeFactory){...} 

    public void process() { 

     while(...){ 
      S current = get(); 
      S old = getOld(); 
      // ... 
      ScoreNode<S> next = this.nodeFactory.create(current,...)); 
      // Comparisons performed 
      if (next.compareByCost(old) <=0){ 
       //... 
      } 
      if (next.compareByScore(old) > 0){ 
       // ... 
      } 
     } 

    } 
} 

, 그리고 밀접 공장 관련이 사용되었습니다 (다른 노드에는 다른 공장이 필요합니다. 및 다른 비교기).

반면에 비교기를 사용하는 경우 CostComparator, ScoreComparator 및 NodeFactory의 세 가지 구성 요소를 클라이언트에 제공해야합니다. 이 시나리오에서는, 나는 단지 Node<S> 을 사용하여 약 CostNode<S>ScoreNode<S> 잊을 수 :이 경우에 나는 클라이언트에 둘 개 이상의 구성 요소 제공하기 때문에

public class ConcreteNodeCostComparator implements Comparator<Node<S>> { 
    public int compare(Node<S> a, Node<S> b){ 
     return Double.compare(((ConcreteNode<S>)a).getCost(), ((ConcreteNode<S>)b).getCost()); 
    } 
} 

public class ConcreteNodeScoreComparator implements Comparator<Node<S>> { 
    public int compare(Node<S> a, Node<S> b){ 
     return Double.compare(((ConcreteNode<S>)a).getScore(), ((ConcreteNode<S>)b).getScore()); 
    } 
} 

그러나, 나는, 정말이 대안 좋아하지 않는다, 비교 방법이 노드에 강하게 의존 할 때

나는이 디자인에서 뭔가를 놓치고 있다고 생각합니다. 당신은 무엇을 생각합니까?

답변

1

연결 한 스레드에서 Boune의 대답을 살펴 봐야합니다. (http://tobega.blogspot.fr/2008/05/beautiful-enums.html)

당신은 당신의 ScoreNode 인터페이스 (또는 다른) 사용에 열거의 종류를 사용할 수 있습니다

ScoreNode.Order.ByCost.compare(node1, node2); 
ScoreNode.Order.ByScore.compare(node1, node2); 

당신은 당신의 클라이언트에 더 이상 구성 요소를 제공 할 필요가 없습니다.

+0

다른 게시물에서 아름다운 열거 형 비교자를 보았습니다. 코드가 우아하지만 문제는 열거 형 내부의 값과 비교하여 ScoreNode의 재사용 가능성을 없애야한다는 것입니다. –

관련 문제