Как использовать общий класс с конкретными объектами в статическом контексте?
Я попытаюсь объяснить в своих силах.
Я использую Play Framework 2, и я сделаю много действий CRUD. Некоторые из них будут identitcal, поэтому я хотел бы KISS и DRY, поэтому сначала я думал об абстрактном классе, содержащем методы list
, details
, create
, update
и delete
, с общий объект и расширьте этот класс, указав, какой объект использовать (Модель и форма):
public abstract class CrudController extends Controller {
protected static Model.Finder<Long, Model> finder = null;
protected static Form<Model> form = null;
public static Result list() {
// some code here
}
public static Result details(Long id) {
// some code here
}
public static Result create() {
// some code here
}
public static Result update(Long id) {
// some code here
}
public static Result delete(Long id) {
// some code here
}
}
И класс, который будет использовать CRUD:
public class Cities extends CrudController {
protected static Model.Finder<Long, City> finder = City.find;
protected static Form<City> form = form(City.class);
// I can override a method in order to change it behavior :
public static Result list() {
// some different code here, like adding some where condition
}
}
Это будет работать, если я не был в статическом контексте.
Но так как это так, как я могу это сделать?
Ответы
Ответ 1
Это может быть достигнуто с помощью делегирования: определите обычный Java-класс, содержащий логику действий CRUD:
public class Crud<T extends Model> {
private final Model.Finder<Long, T> find;
private final Form<T> form;
public Crud(Model.Finder<Long, T> find, Form<T> form) {
this.find = find;
this.form = form;
}
public Result list() {
return ok(Json.toJson(find.all()));
}
public Result create() {
Form<T> createForm = form.bindFromRequest();
if (createForm.hasErrors()) {
return badRequest();
} else {
createForm.get().save();
return ok();
}
}
public Result read(Long id) {
T t = find.byId(id);
if (t == null) {
return notFound();
}
return ok(Json.toJson(t));
}
// … same for update and delete
}
Затем вы можете определить контроллер воспроизведения, имеющий статическое поле, содержащее экземпляр Crud<City>
:
public class Cities extends Controller {
public final static Crud<City> crud = new Crud<City>(City.find, form(City.class));
}
И вы почти закончили: вам просто нужно определить маршруты для действий Crud:
GET / controllers.Cities.crud.list()
POST / controllers.Cities.crud.create()
GET /:id controllers.Cities.crud.read(id: Long)
Примечание: этот пример создает ответы JSON для краткости, но его можно визуализировать HTML-шаблоны. Однако, поскольку шаблоны Play 2 статически типизированы, вам необходимо передать все их как параметры класса Crud
.
Ответ 2
(Отказ от ответственности: у меня нет опыта работы с playframework.)
Следующая идея может помочь:
public interface IOpImplementation {
public static Result list();
public static Result details(Long id);
public static Result create();
public static Result update(Long id);
public static Result delete(Long id);
}
public abstract class CrudController extends Controller {
protected static Model.Finder<Long, Model> finder = null;
protected static Form<Model> form = null;
protected static IOpImplementation impl;
public static Result list() {
return impl.list();
}
public static Result details(Long id) {
return impl.details(id);
}
// other operations defined the same way
}
public class Cities extends CrudController {
public static Cities() {
impl = new CitiesImpl();
}
}
Таким образом вы можете создать иерархию реализаций.
(Это должен быть какой-то причудливый дизайн, но я не знаю имя ATM.)