2012-05-22 13 views
10

Spróbuję wyjaśnić, jak najlepiej.Jak używać klasy ogólnej dla określonych obiektów w kontekście statycznym?

Używam Play Framework 2, a zrobię dużo akcji CRUD. Niektóre z nich będą identyczne, więc chciałbym KISS i SUCHY, więc na początku myślałem o klasie abstrakcyjnej zawierającej metody ogólne z rozszerzeniem tej klasy, określając, które obiekt w użyciu (model & Form):

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 
    } 
} 

I klasa, która będzie wykorzystywać 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 
    } 
} 

to będzie działać, jeśli nie był w statycznym kontekście.

Ale jak to się dzieje, jak mogę to zrobić?

+0

Dlaczego nie po prostu przejść do metod instancji? Dziedziczenie nie działa na metodach klas w Javie. – Vlad

+0

Inną ideą może być zastąpienie dziedziczenia kompozycją: wystarczy mieć instancje CrudController i delegować operacje do określonego obiektu związanego z instancją. (Wszystko zależy oczywiście od twojego projektu.) – Vlad

+0

@Vlad: Na pierwsze pytanie nie mogę, Play wymaga statycznej metody dla kontrolera. Teraz na drugi, nie jestem pewien, aby zrozumieć, czy mógłbyś rozwinąć (lub stworzyć nową odpowiedź)? –

Odpowiedz

13

ten może zostać osiągnięty za pomocą delegacji: zdefiniować regularne klasy Java zawierające logikę powództw 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 
} 

Następnie można określić kontroler Odtwórz mający statycznego pola zawierającego wystąpienie Crud<City>:

public class Cities extends Controller { 
    public final static Crud<City> crud = new Crud<City>(City.find, form(City.class)); 
} 

a ty prawie gotowy: wystarczy trzeba określić trasy dla działań CRUD:

GET /     controllers.Cities.crud.list() 
POST /     controllers.Cities.crud.create() 
GET  /:id     controllers.Cities.crud.read(id: Long) 

Uwaga: Ten przykład wywołuje reakcje JSON dla brevety ale możliwe do renderowania szablonów HTML. Ponieważ jednak szablony Play 2 są statycznie wpisane, musisz przekazać je wszystkie jako parametry klasy Crud.

+0

Imo, zwracając widok w zależności od kontrolera, jest trudną częścią, jak byś to rozwiązał? –

+0

To rzeczywiście interesujący problem. Pytanie to dotyczyło raczej ponownego wykorzystania pewnej logiki pomimo statycznego charakteru kontrolerów (co uniemożliwia dziedziczenie). Może powinieneś otworzyć kolejne pytanie? –

+1

To prawda, nie wchodzi to w zakres tego pytania. Ale po prostu zastanawiałeś się, kiedy czytasz swoją odpowiedź, którą lubię! Może dziś wieczorem otworzę kolejne pytanie. –

4

:

Poniższy pomysł może pomóc (Zastrzeżenie mam żadnego doświadczenia z 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(); 
    } 

} 

W ten sposób można stworzyć hierarchię wdrożeń.

(To musi być jakiś fantazyjny nazwie wzornictwo, ale nie wiem, nazwa bankomatu.)

+0

Za twoją odpowiedzią kryje się niezły pomysł, ale szukam klasy, którą mam zmodyfikować w bazie danych (miasta itp.). Ponieważ kiedy definiuję trasy, muszę wskazać im określoną klasę (kontroler). Ten kontroler określi, który model będzie używany. Więc nie ma problemu, jeśli CrudController się zmieni, po prostu muszę napisać tak mało kodu jak to możliwe dla każdego kontrolera Crud dla przypadku, gdy kod jest identyczny pomiędzy różnymi klasami. –

+0

@ cx42net: Nie rozumiem części "posiadanie klasy według modelu". Czy to oznacza, że ​​dla każdego możliwego "Modelu" powinna istnieć jedna klasa wyprowadzona z 'CrudController' (lub może jedna instancja' CrudController')? – Vlad

+0

Och, to by nie działało, ponieważ nie ma żadnych instancji. Zaczekaj, zaktualizuję to. – Vlad

Powiązane problemy