Java Hibernate Spring - Сервисный интерфейс с реализацией по умолчанию - PullRequest
0 голосов
/ 28 октября 2019

У меня есть приложение базы данных Java, использующее hibernate, с разными классами, которые имеют одинаковые атрибуты (здесь: «активный»). В интерфейсе есть функция, которая извлекает записи из базы данных на основе такого атрибута (активный). До сих пор я делал это:

//interface
public interface ObjSvcIntf {
   default <Entity> ArrayList<Entity> get(Boolean active);
}
//implementation 1
public class ObjCarSvc implements ObjSvcIntf {

   @SuppressWarnings("unchecked")
   @Override
   public ArrayList< ObjCar > get(Boolean active) {
       @SuppressWarnings("rawtypes")
       Query query = DB.s.createQuery("from " + ObjCar.class.getSimpleName() + " where active = :active");
       query.setParameter("active", active);

       if (!query.list().isEmpty()) {
           return (ArrayList< ObjCar >) query.list();  
       } else {
           return null;
       }


   }

//implementation 1
public class ObjPersonSvc implements ObjSvcIntf {

   @SuppressWarnings("unchecked")
   @Override
   public ArrayList< ObjPerson > get(Boolean active) {
       @SuppressWarnings("rawtypes")
       Query query = DB.s.createQuery("from " + ObjPerson.class.getSimpleName() + " where active = :active");
       query.setParameter("active ", active);

       if (!query.list().isEmpty()) {
           return (ArrayList< ObjPerson >) query.list();   
       } else {
           return null;
       }


   }

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

public interface ObjSvcIntf {

   default <Entity> ArrayList<Entity> get(Boolean active) {
       @SuppressWarnings("rawtypes")
       Query query = DB.s.createQuery("from " + Entity.class.getSimpleName() + " where active = :active");
       query.setParameter("active", active);

       return (ArrayList<Entity>) query.list();
   }

}

Мне не хватает правильного понимания здесь, как правильно создать функцию в интерфейсе, чтобы иметь возможностьиспользовать его в разных контекстах / разных классах.

Как вместо этого настроить функцию в интерфейсе, чтобы это произошло?

Ответы [ 3 ]

0 голосов
/ 28 октября 2019
public interface ObjSvcIntf<Entity> {
    default <Entity> ArrayList<Entity> get(Boolean active) {
        @SuppressWarnings("rawtypes")
        Query query = DB.s.createQuery("from " + getImplClass().getSimpleName() + " where active = :active");
        query.setParameter("active", active);
        return (ArrayList<Entity>) query.list();
    }
    Class getImplClass();
}

И вы можете просто предоставить тот же класс для каждой реализации, что и для универсального типа.

0 голосов
/ 30 октября 2019

Я реструктурировал проект, чтобы отделить Интерфейс от его реализации. Каждый класс, расширяющий (абстрактную) реализацию интерфейса, теперь устанавливает атрибут типа «Класс» при вызове супер-конструктора, причем каждая функция в абстрактном классе ссылается на этот атрибут.

Есть ли лучший способ? Каковы потенциальные проблемы с этим подходом?

Интерфейс:

public interfaceObjSvcIntf {

    <Entity> Object getById(Long id);

}

Реализация абстрактного класса:

public abstract class ObjSvcImpl implements ObjSvcIntf {

    public Class<?> servicedClass;

    // CONSTRUCTOR
    public ObjSvcImpl(Class<?> servicedClass) {
        this.servicedClass = servicedClass;
    }

    @Override
    public <Entity> Object getById(Long id) {
         return DB.getById(this.servicedClass, id);
    }
}

Класс обслуживания:

public class ObjCarSvc extends ObjSvcImpl {

    public ObjCarSvc() {
        super(ObjCar.class);
    }

}

Класс модели:

@Entity
@Table(name = "OBJ_CAR")
public class ObjCar implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "OBJ_CAR_ID")
    private Long objCarId;

    @NotNull
    @Column(name = "NAME")
    private String name;

    // Getters and Setters
}
0 голосов
/ 28 октября 2019

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

public interface ObjSvcIntf<E> {
    default List<E> get(Boolean active) {
        var list = new ArrayList<E>();
        list.add(self());
        return list;
    }

    E self(); // function to return the sub class instance
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...