【问题标题】:How to create 2 depends Comparators in java?如何在java中创建2个依赖比较器?
【发布时间】:2016-01-10 12:51:05
【问题描述】:

假设我在 Java 中有一个 Product 类和 2 个 Comparators:

  1. 第一个是价格Comparator asc 订单。
  2. 第二个是价格Comparator desc order。

如果我将第一个更改为产品名称Comparator,那么第二个将自动更改为名称Comparator

非常感谢!

示例:

class ProductComparatorByPriceDesc implements Comparator<Customer> {
        @Override
        public int compare(Product o1, Product o2) {
             return o1.getPrice() - o2.getPrice();
        }
    }

Class ProductComparatorByPriceAsc implements Comparator<Customer> {
    @Override
    public int compare(Customer o1, Customer o2) {
        return o2.getPrice() - o1.getPrice();
    }
}

因此,如果我将第一个比较器更改为按名称而非价格排序,那么第二个也会更改,但不会相反!

【问题讨论】:

  • 我不明白...
  • 我不明白你的问题,恐怕。如果您可以发布 minimal reproducible example 会有所帮助。
  • 添加示例,可以吗? @乔恩斯基特
  • 好吧,目前尚不清楚您希望一个比较器中的代码更改如何在另一个比较器中更改 - 但无论如何您都不需要两个比较器。将添加一个答案。
  • @JonSkeet ,我知道,但这是我们要求的,我一无所知!

标签: java sorting interface comparator


【解决方案1】:

一种方法是:

import java.util.*;

class SomeClass {
  public int price;
  public String name;
  public SomeClass(String name, int price) {
    this.name = name;
    this.price = price;
  }
}

class PriceOrNameComparator implements Comparator<SomeClass> {

  boolean compareByPrice;

  public PriceOrNameComparator byPrice() {
    this.compareByPrice = true;
    return this;
  }

  public PriceOrNameComparator byName() {
    this.compareByPrice = false;
    return this;
  }

  public int compare(SomeClass a, SomeClass b) {
    if (compareByPrice) {
      return a.price - b.price;
    } else {
      return a.name.compareTo(b.name);
    }
  }

  public Comparator<SomeClass> reverseComparator() {
    return new Comparator<SomeClass>() {
      public int compare(SomeClass a, SomeClass b) {
        int res = PriceOrNameComparator.this.compare(a, b);
        if (res == 0) {
          return 0;
        } else {
          return (res > 0) ? -1 : 1;
        }
      }
    };
  }
}

class Test {
  public static void main(String[] args) {
    SomeClass s1 = new SomeClass("a", 5);
    SomeClass s2 = new SomeClass("b", 4);
    PriceOrNameComparator c = new PriceOrNameComparator().byPrice();
    Comparator<SomeClass> r = c.reverseComparator();
    System.out.println(c.compare(s1, s2)); // 1
    System.out.println(r.compare(s1, s2)); // -1
    c.byName();
    System.out.println(c.compare(s1, s2)); // -1
    System.out.println(r.compare(s1, s2)); // 1
  }
}

基本上,外部比较器是可配置的,内部的倒序比较器是一个匿名的内部类,对外部比较器有一个隐式引用,并且可以观察其状态的变化。

【讨论】:

  • 谢谢,但我的意思是在代码中如果我从价格更改为名称,那么其他比较器也会更改,但它只会以一种方式。我的意思是,如果另一个比较器将更改当前字段,则第一个比较器不会更改它。 @弗拉德
  • @ShayZambrovski:您是在谈论更改比较器的代码,还是在执行时更改其中的某些状态?
  • 就个人而言,这个答案违反了单一责任原则。我认为用小的构建块进行比较更清楚,然后将它们链接在一起。此外,您的反向比较器已损坏 - 请参阅 blogs.msdn.microsoft.com/ericlippert/2011/01/24/…
  • @JonSkeet,不是乔恩,我说的是设计时间
  • @ShayZambrovski:在这种情况下,只需要一个类,然后如果你改变它的代码,它会改变所有使用它的东西......
【解决方案2】:

我建议只使用一个比较器类来按价格进行比较,并使用一个单独的比较器类来按名称进行比较(或者没有类 - 请参阅我的答案的结尾)。每个班级都做一件事,而且做得很好。

然后您可以使用Comparator.reversed 默认方法反转任何 比较器...同样您可以使用Comparator.thenComparing 将它们链接在一起,如果您希望按名称和价格订购,则为示例:

Comparator<Product> nameThenPrice =
    new NameComparator().thenComparing(new PriceComparator());

(如果您不使用 Java 8,编写一个 ReversingComparator 和一个 CompoundComparator 使用现有的两个是很容易的。)

您还可以在Comparator 中使用Java 8 的静态方法:

Comparator<Product> byName = Comparator.comparing(p -> p.getName());
Comparator<Product> byPrice = Comparator.comparing(p -> p.getPrice());
Comparator<Product> nameThenPrice = byName.thenComparing(byPrice);

这样您通常根本不需要手动实现Comparator

【讨论】:

  • 反转只是另一个比较器的示例
  • @ShayZambrovski:我们如何从这个问题中知道这一点?我们只能回答实际提出的问题......
  • 非常感谢,我仍然不能为你投票,但我会尽快投票!
  • @ShayZambrovski 您无法投票,但如果此解决方案解决了您的问题,您仍然可以接受。
猜你喜欢
  • 2022-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多