Как создать универсальный интерфейс Java, набранный с помощью другого универсального интерфейса Java? - PullRequest
1 голос
/ 18 мая 2019

Целью нашего подхода является внедрение интерфейсов в существующие классы DAO и модели. Классы модели идентифицируются с помощью идентификаторов ресурсов различных типов, а идентификаторы ресурсов - это не просто случайные числа, но несут семантику и поведение. Таким образом, мы должны представлять идентификаторы ресурсов объектами, а не примитивными типами.

Текущий подход для идентификаторов ресурсов:

interface ResourceId<T> {
  T get();
}
class UserId implements ResourceId<String> {
  public String get();
}

Текущий подход для наших ресурсов / моделей:

interface Resource<I extends ResourceId> {
  I id();
}
class User implements Resource<UserId> {
  public UserId id();
}


Я изо всех сил пытаюсь найти рабочее решение для наших классов DAO. Вот несколько подходов, которые я пробовал, но не смог:

=== Вариант 1 ===
не удается с:
error: > expected
несколько уровней универсальных типов кажутся запрещенными в Java

interface Dao<R extends Resource<I extends ResourceId>> {
  R findById(I id);
  void save(R u);
}
class UserDao implements Dao<User> {
  public User findById(UserId id);
  public void save(User u);
}

=== Вариант 2 ===
не удается с:
UserDao is not abstract and does not override abstract method <R>save(R) in Dao
Также Дао выглядит глупо. UserDao должен быть объектом Dao .

interface Dao<I extends ResourceId> {
  <R extends Resource<I>> R findById(I id);
  <R extends Resource<I>> void save(R u);
}
class UserDao implements Dao<UserId> {
  public User findById(UserId id);
  public void save(User u);
}

=== Вариант 3 ===
не удается с:
UserDao is not abstract and does not override abstract method <I>findById(I) in Dao Даже если это сработало, я не привязан к ResourceId, фактически реализованному R.

interface Dao<R extends Resource> {
  <I extends ResourceId> R findById(I id);
  void save(R u);
}
class UserDao implements Dao<User> {
  public User findById(UserId id);
  public void save(User u);
}

=== Вариант 4 ===
компилирует.
Однако #findById в UserDao должен принимать универсальный параметр типа ResourceId вместо UserId. Кроме того, внутри реализации #findById мы должны были бы привести результат #get () к String.
Обычно проблема заключается в том, что тип ResourceId не связан с ResourceId, фактически реализованным в R.

interface Dao<R extends Resource> {
  R findById(ResourceId id);
  void save(R u);
}
class UserDao implements Dao<User> {
  public User findById(ResourceId id);
  public void save(User u);
}

=== Вариант 5 ===
компилирует.
Однако Dao выглядит глупо. Информация о том, какой ResourceId мы хотим использовать (т. Е. UserId), уже доступна при реализации Ресурса (т. Е. User). Нет ли более чистого пути?

interface Dao<R extends Resource, I extends ResourceId> {
  R findById(I id);
  void save(R u);
}
class UserDao implements Dao<User, UserId> {
  public User findById(UserId id);
  public void save(User u);
}

Есть идеи, как правильно решить эту проблему?

1 Ответ

2 голосов
/ 18 мая 2019

Ваш первый вариант сработает, просто найдите, настроив его соответствующим образом. Сначала добавьте спецификацию обобщенного типа ResourceId в ваше объявление Dao:

    static interface Dao<I extends ResourceId<?>, R extends Resource<I>> {
        R findById(I id);

        void save(R u);
    }

и затем сделайте то же самое с подклассами Dao:

    static class UserDao implements Dao<UserId, User> {
        public User findById(UserId id) { return null; }

        public void save(User u) {}
    }

Поскольку вам не нужно знать, что является универсальным типом ResourceId (<T>) в контексте класса Resource, вы можете просто отклонить его там с помощью подстановочного знака:

    static interface Resource<I extends ResourceId<?>> {
        I id();
    }

Наконец, полный код будет скомпилирован как:

public class NestedGenerics {

    static interface ResourceId<T> {
        T get();
    }

    static class UserId implements ResourceId<String> {
        public String get() { return null; } 
    }

    static interface Resource<I extends ResourceId<?>> {
        I id();
    }

    static class User implements Resource<UserId> {
        public UserId id() { return null; } 
    }

    static interface Dao<I extends ResourceId<?>, R extends Resource<I>> {
        R findById(I id);

        void save(R u);
    }

    static class UserDao implements Dao<UserId, User> {
        public User findById(UserId id) { return null; }

        public void save(User u) {}
    }
}

Надеюсь, это поможет.

...