简体   繁体   English

正确使用Comparable与泛型

[英]Proper use of Comparable with generics

I'm having trouble getting an interface to work the way I want using generics. 我在使接口以我想要使用泛型的方式工作时遇到了麻烦。

I have a CRUD-style interface to handle data access of various objects. 我有一个CRUD风格的界面来处理各种对象的数据访问。 Comparable<?> is used for getting objects by identifier since objects may have identifiers of different types: Comparable<?>用于通过标识符获取对象,因为对象可能具有不同类型的标识符:

public interface DataProvider<T> {
  T create(T object);
  T get(Comparable<?> id);
  void update(T object);
  void delete(T object);
}

Now imagine one such (contrived) object that needs to be accessed, Book : 现在想象一个需要访问的此类(人为)对象Book

public class Book implements Comparable<Book> {

  private ISBN isbn;

  public int compareTo(Book other) {
    return getIsbn().compareTo(other.getIsbn());
  } 

  // ...
}

What I would like to be able to do is this: 我想做的是这样的:

public class BookDataProvider implements DataProvider<Book> {
  public Book create(Book book) { ... }
  public Book get(ISBN isbn) { ... }
  public void update(Book book) { ... }
  public void delete(Book book) { ... }
}

What's the simplest way to modify DataProvider and/or Book to allow get(ISBN) to compile? 修改DataProvider和/或Book以允许get(ISBN)编译的最简单方法是什么?

I've come up with a couple partial solutions, but I'm not sure either is optimal: 我已经提出了一些部分解决方案,但是我不确定哪一个是最佳的:

  • Type DataProvider as DataProvider<T, I extends Comparable<I>> , but this adds an extra type parameter. 键入DataProvider作为DataProvider<T, I extends Comparable<I>> ,但是这增加了额外的类型参数。
  • Introduce an Identifiable interface per this related post , make Book implement it, and type DataProvider as DataProvider<T extends Identifiable<?>> , but then I don't achieve the signature for get(ISBN) . 在每个相关文章中引入一个Identifiable接口,使Book实现它,并在DataProvider<T extends Identifiable<?>>键入DataProvider ,但是然后我没有实现get(ISBN)的签名。

Ideally I would like to limit DataProvider to have only one type parameter. 理想情况下,我想限制DataProvider仅具有一个类型参数。 I'm open to other approaches as well. 我也对其他方法持开放态度。 Thanks. 谢谢。

Using Comparable as a parameter in application specific getter method is not appropriate. 使用具有可比性的专用getter方法的参数是不恰当的。 Ideally your get method is not supposed to work for any Comparable. 理想情况下,您的get方法不应适用于任何Comparable。 It is only for particular types like ISBN. 仅适用于ISBN等特定类型。 SO I suggest instead of struggling for Comparable generics, go for common interface for such identifiers. 因此,我建议不要为可比较的泛型而苦苦挣扎,而应使用此类标识符的通用接口。

Lets take 2nd approach from your partial options & create one solution. 让我们从部分选项中采用第二种方法并创建一个解决方案。 Below is code that I suggest. 下面是我建议的代码。

public class TestGenerics {
    public static void main(String[] args) {

    }
}

interface Identifiable<T extends Identifier> {
    T getIdentifier();
}

interface Identifier {

}

class Book implements Comparable<Book>, Identifiable<ISBN> {

    private ISBN isbn;

    public int compareTo(Book other) {
        return getIdentifier().compareTo(other.getIdentifier());
    }

    public ISBN getIdentifier() {

        return null;
    }

}

class ISBN implements Comparable<ISBN>, Identifier {

    public int compareTo(ISBN o) {
        return 0;
    }

}

interface DataProvider<T extends Identifiable<? extends Identifier>> {
    T create(T object);

    T get(Identifier id);

    void update(T object);

    void delete(T object);
}

class BookDataProvider implements DataProvider<Book> {

    public Book create(Book book) {
        return null;
    }

    public void update(Book book) {
    }

    public void delete(Book book) {
    }

    public Book get(Identifier id) {
        // TODO Auto-generated method stub
        return null;
    }

}

Now this approach is truly generic because now at top level you have interfaces Identifiable & Identifier which means, every Identifiable (eg. book, pdf etc) must have some Identifier (eg. ISBN, bookNumber etc). 现在,这种方法是真正通用的,因为在顶层,您已经有了Identifiable&Identifier接口,这意味着每个Identifiable(例如book,pdf等)都必须具有一些Identifier(例如ISBN,bookNumber等)。

Now you implement this top level hierarchy with Book as Identifiable & ISBN as Identifier. 现在,您可以使用Book作为Identifiable和ISBN作为Identifier来实现此顶层层次结构。 THis will be your implementation layer. 这将是您的实施层。

Then you create DataProvider interface for Identifiable mentioned in generics. 然后,您为泛型中提到的Identifiable创建DataProvider接口。 Its get method will have Identifier as parameter ie if DataProvider is for Book then its get method will be for ISBN. 它的get方法将以标识符作为参数,即如果DataProvider用于Book,则其get方法将用于ISBN。

Now here you implement DataProvider with BookDataProvider. 现在,您在此处使用BookDataProvider实现DataProvider。 In this class, you won't get ISBN as parameter, but instead you will have Identifier as parameter. 在此类中,您不会将ISBN作为参数,而是将标识符作为参数。 You can pass ISBN in it as it is a Identifier. 您可以在其中传递ISBN,因为它是一个标识符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM