2012-05-22 1 views
10

私はベストに説明しようとしています。静的コンテキストで特定のオブジェクトに汎用クラスを使用するにはどうすればよいですか?

私はPlay Framework 2を使用しています。私は多くのCRUDアクションを行います。それらのうちのいくつかは同一であるため、私はKISSとDRYをしたいと思います。最初に、listdetailscreateupdatedeleteのメソッドを汎用オブジェクトと共に含む抽象クラスについて考えていました。

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

単にインスタンスメソッドに切り替えるのはなぜですか?継承は、Javaのクラスメソッドでは機能しません。 – Vlad

+0

継承をコンポジションに置き換えることもできます:CrudControllerのインスタンスを持って、そのインスタンスに含まれるオブジェクトに操作を委譲するだけです。 (これはすべてあなたのデザインに依存します) – Vlad

+0

@Vlad:最初の質問では、再生できません。再生にはコントローラの静的メソッドが必要です。今度は第二に、私は理解していない、あなたは精巧な(または新しい答えを作る)ことができますか? –

答えて

13

これは、委任を使用して達成することができます:CRUD操作ロジックを含む通常のJavaクラスを定義します。

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

そして、あなたはほぼ完了している:あなただけ

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

注:この例では、簡潔にJSON応答を生成しますが、HTMLテンプレートをレンダリングすることは可能です。ただし、Play 2テンプレートは静的に型指定されているため、すべてをCrudクラスのパラメータとして渡す必要があります。

+0

コントローラに応じてビューを返すのは難しい部分ですが、どうすればそれを解決できますか? –

+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(); 
    } 

} 

この方法であなたは、実装の階層を作成することができます。

(これは、いくつかの派手な名前のデザインパターンでなければなりませんが、私は名前のATMを知りません。)

+0

あなたの答えの背後にある素晴らしいアイデアがありますが、私が探しているのは、データベース(都市など)を変更するためのModelクラスです。ルートを定義するときに、特定のクラス(コントローラ)をポイントする必要があるためです。このコントローラは、使用するモデルを定義します。 CrudControllerが変更されても問題にはならないので、さまざまなクラス間でコードが同一である場合は、Crudコントローラごとに可能な限り小さなコードを記述するだけです。 –

+0

@ cx42net: "Model by class"の部分は分かりませんでした。これは、それぞれの可能な 'Model'に対して、' CrudController'(または 'CrudController'の1つのインスタンス)から派生した1つのクラスが存在することを意味しますか? – Vlad

+0

インスタンスが存在しないので、これは機能しません。待って、私はそれを更新します。 – Vlad

関連する問題