2016-12-07 4 views
1

私はかなり独特な設計上の問題に悩まされています。私は、Java ORMを使用していて、次のように私のモデルクラスのいずれかを定義しています継承とインターフェイスに関する設計上の混乱

class User extends Model { 
    // . . . 
} 

は今、より多くのモデルがあり、私はそれらすべてのデータの検証をサポートしたいと思います。アイデアは簡単です:各セッターメソッドが呼び出されると、エラーの内部ArrayListが生成され続けます。

エラー処理のメカニズムは、すべてのモデルクラスでまったく同じです。私は、次のインターフェイスを思い描くことができます。

public interface ErrorReportable { 
    ArrayList<String> errors = new ArrayList<String>(); 

    boolean hasErrors(); 

    ArrayList<String> getErrors(); 

    void resetErrors(); 
} 

は、今私は問題を抱えている:すべてのメソッドは抽象的で、私は私のクラスでは、それらのすべての実装を提供する必要がありますを意味しています。これは悲しいことです。これらのメソッドは全く同じ方法で実装されるためです。理想的には、これは私がうまく継承した別のクラスでしたが、悲しいことに、Javaでは多重継承はありません。

私の次のオプションは、インターフェイスのデフォルトメソッドを使用していますが、問題はerrorsフィールドです。これは静的になりますが、各インスタンスには通常のフィールドが必要です。

唯一の解決策のようですが、にhasErrors()メソッドがある必要があります。これはreturn this.error_obj.hasErrors()になります。これはうまくいきますが、私が物事を二度書く必要があるので、私の意見では本当にきれいではありません。

どうすればよいですか?

+0

実際にバリデーションをセッターですぐに実行しますか? setterが2回呼び出され、最初に無効な値を提供するが、2回目の呼び出しで有効な値はどうなるでしょうか?また、クロスフィールドバリデーションが必要になった場合、セッターで検証することは悪夢になります。 –

+0

@JiriTousek私が言う限り、それは起こりません。これは典型的なWebアプリケーションであり、コントローラはフィールドを1つずつ入力します。最後に、コントローラは 'hasErrors()'を呼び出し、応答をフロントエンドに返します。右のデータが来る次のサイクルでは、新しいオブジェクトがインスタンス化されます。しかし、私が要求に応じて検証を実行することを選択したとしても、デザインパズルは変わらないと思います。 – dotslash

答えて

1

私はそれだけでList<Error> validate()メソッドを公開するモデルクラスのために良いだろう、とすべてのフィールドを検証し、エラーを収集し、スタンドアローンのバリデータを持っていると思います。

このようにして、収集されたメッセージはモデルの状態の一部ではなく、検証がいつ行われるかを明示的に制御します。コンポジション(ほとんどいつでも良いことです)と必要な唯一の方法モデルクラスで実装するのはエンティティ固有の検証です。

クロスフィールドのバリデーションを追加する必要がある場合は、このデザインをフィールドバリデーションと並行して実行することも非常に簡単です。

+0

それはたくさんの意味があります!私は、クロスフィールド検証のアイデアによって確信していました。モデルにはリレーションシップがあるので、両方のクラスにバリデータが埋め込まれていると、モデルが役に立ちます。 – dotslash

1

私があなたの必要性を得たならば、私はすべてのネイタタリインターフェースを実装し、モデル祖先を拡張する独自のModel-classを実装しますが、依然としてAbstractです。

すべての通常のモデルクラスは抽象モデルクラスから継承し、インタフェースの実装とモデルクラス(第2世代)の継承を継承します。 'instance of'でチェックされているフレームワークであれば、それ以降のモデルクラスでもtrueをチェックします。

抽象クラスは、抽象メソッド/メンバーを持つ必要はありませんが、そのクラスから直接インスタンス化されないように抽象クラスを維持する必要があります。

public abstract class myModel extends Model implements ErrorReportable{ ... } 

public class User extends myModel { ... } 
+0

非常に良い!私はこの解決策がほぼそこにあると感じますが、なぜ抽象クラスですか?どのメソッドも抽象化されることはありません。彼らはすべてすべてのモデルで全く同じ実装を持っています。だから私は普通のクラスを定義し、それはトリックを行うだろうと思いますか? – dotslash

+0

myModelクラスが野外にあるのを避けたいのであれば(これは、Logクラスのインスタンス上でmyModelのインスタンスが使用されていないためかもしれません)、抽象クラスを使用します。 抽象クラスである必要はありませんが、そのデザインクラスのコンストラクタを呼び出すことを避けることができます。そのコンストラクタは、インスタンスとしてインスタンスを持つことはありません。 – nxthor

関連する問題