通常,当您想要使用不同属性比较对象时,比较器是最佳选择 (参见例如How to compare objects by multiple fields)。 但是,在我的特殊情况下,我不确定使用比较器。
问题如下:我已经定义了一个名为Node<S>
的通用接口,它是共享的
通过不同的组件。还有一个CostNode<S>
扩展了Node<S>
和ScoreNode<S>
它扩展了CostNode<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());
}
}
但是,我并不喜欢这种替代方案,因为在这种情况下我必须再提供两个组件 到客户端时,比较方法很大程度上取决于节点。
我想我在这个设计中缺少一些东西。你怎么看?
答案 0 :(得分:1)
你应该在你联系的主题中看看Boune的回答。 (http://tobega.blogspot.fr/2008/05/beautiful-enums.html)
您可以在ScoreNode界面(或其他地方)使用这种枚举,并使用:
ScoreNode.Order.ByCost.compare(node1, node2);
ScoreNode.Order.ByScore.compare(node1, node2);
您无需再向客户提供任何组件。