2012-05-22 1 views
10

Я попытаюсь объяснить в своих силах.Как использовать общий класс с конкретными объектами в статическом контексте?

Я использую Play Framework 2, и я сделаю много действий CRUD. Некоторые из них будут identitcal, поэтому я хотел бы использовать KISS и DRY, поэтому сначала я думал об абстрактном классе, который содержит методы list, details, , 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's behavior : 
    public static Result list() { 
     // some different code here, like adding some where condition 
    } 
} 

Это будет работать, если бы я не был в статическом контексте.

Но так как это так, как я могу это сделать?

+0

Почему бы просто не переключиться на методы экземпляра? Inheritance не работает над методами класса в Java. – Vlad

+0

Еще одна идея - заменить наследование композицией: просто иметь экземпляры CrudController и делегировать операции конкретному содержащему объект экземпляру. (Это все зависит от вашего дизайна, конечно.) – Vlad

+0

@ Vlad: По первому вопросу, я не могу, Play требуется статический метод для контроллера. Теперь, во-вторых, я не уверен, что понимаю, не могли бы вы разработать (или создать новый ответ)? –

ответ

13

Это может быть достигнуто с помощью делегирования: определить регулярный класс 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 для brevety, но это возможно, чтобы сделать шаблоны HTML. Однако, поскольку шаблоны Play 2 статически типизированы, вам необходимо передать все их в качестве параметров класса Crud.

+0

Imo, возвращающий представление в зависимости от контроллера, является сложной частью, как бы вы решили это? –

+0

Это действительно интересная проблема. Этот вопрос был больше о том, как повторно использовать некоторую логику, несмотря на статический характер контроллеров (которые запрещают наследование). Может, вам стоит открыть еще один вопрос? –

+1

Правда, дело не в этом вопросе. Но было просто интересно, когда читаешь свой ответ, который мне нравится! Возможно, сегодня я открою еще один вопрос. –

4

:

Следующая идея может помочь (Отказ от ответственности У меня нет опыта работы с 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(); 
    } 

} 

Таким образом, вы можете создать иерархию реализаций.

(Это должно быть некоторые фантазии именем шаблон дизайна, но я не знаю название банкомата.)

+0

За вашим ответом есть какая-то хорошая идея, но то, что я ищу, - это класс от Model для изменения в базе данных (города и т. Д.). Потому что, когда я определяю маршруты, мне нужно указать их на определенный класс (контроллер). Этот контроллер определит, какую модель использовать. Поэтому это не проблема, если CrudController изменяется, мне просто нужно написать как можно меньше кода для каждого контроллера Crud для случая, когда код идентичен между различными классами. –

+0

@ cx42net: Я не понял часть «с классом по модели». Означает ли это, что для каждой возможной «Модели» должен быть один класс, полученный из «CrudController» (или, возможно, один экземпляр «CrudController»)? – Vlad

+0

О, это не сработает, поскольку нет экземпляров. Подождите, я обновлю его. – Vlad

Смежные вопросы