2

というクラスを検証したいPerson。私は次のように書くことができます:

class Person {
  ...
  public boolean isValid() {
    return (name != null && age > 0);
  }
}

ただし、私のプレゼンテーション層では、検証が失敗した具体的な理由をユーザーに示したいと考えています。

私が思いついた解決策は次のとおりです。

  1. isValid()エラーに固有の例外をスローする
  2. ブール値ではなく列挙型をisValid()返すPersonValidationError
  3. プレゼンテーション レイヤーで検証ロジックを複製する

これを処理する最善の方法が何であるかを知りたいです。また、Java 標準ライブラリはこのような状況にどのように対処していますか?

4

4 に答える 4

2

私のソリューションを提示する前のいくつかのポイント:

  1. 例外は、多かれ少なかれ例外的な条件に使用する必要があります。あなたのおっしゃる通り、ユーザーが間違ったデータを送信することは珍しくありません。

  2. クラスが成長するPersonと、それが有効であるために満たさなければならない条件がどんどん追加されます。

  3. 例外を除いて、一度に 1 つのエラーしか表示できません。送信されたデータに複数の問題がある場合はどうなりますか?

  4. クラスに検証メソッドを配置するのPersonは正しくないようです。たとえば、アプリ内のさまざまな場所にさまざまな検証ポリシーを設定したい場合はどうでしょうか?

したがって、 Person クラスを検証ロジックから解放します。

class Person {

    final String name;
    final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

次に、人を受け取って検証するクラスを実装します。アイデアは、それぞれ独自の検証ルールと独自の検証メッセージを持つさまざまなバリデーターを持つことです。enumそれを達成するのに最適です:

enum Validator {

    NOT_NULL_NAME("Name must not be null") {
        @Override
        public boolean validate(Person person) {
            return person.name != null;
        }
    },
    AGE_GREATER_THAN_ZERO("Age must be greater than zero") {
        @Override
        public boolean validate(Person person) {
            return person.age > 0;
        }
    };

    final String errorMessage;

    private Validator(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public abstract boolean validate(Person person);
}

別のメッセージを含む新しい条件を簡単に追加できることがわかりますか? 単なる別の列挙型インスタンス。

次に、人を検証するためのクラスを作成します。すべてのバリデーターをループして、エラー メッセージを収集するだけです。

class PersonValidator {

    private final List<String> errors = new ArrayList<String>();

    public PersonValidator(Person person) {
        for (Validator validator : Validator.values()) {
            if (!validator.validate(person)) {
                errors.add(validator.errorMessage);
            }
        }
    }

    public boolean isValid() {
        return errors.isEmpty();
    }

    public Collection<String> getErrors() {
        return errors;
    }
}

使用方法の例:

public static void main(String... args) {
    Person[] people = { new Person(null, 0), 
                         new Person(null, 42), 
                         new Person("Joe", 0), 
                         new Person("Joe", 42) };
    for (int i = 0; i < people.length; i++) {
        PersonValidator validator = new PersonValidator(people[i]);
        System.out.println(String.format("Person no %s is %s valid. %s", 
              i, 
              validator.isValid() ? "" : "not", 
              Joiner.on(", ").join(validator.getErrors())));

    }
}

上記のプリント:

Person no 0 is not valid. Name must not be null, Age must be greater than zero
Person no 1 is not valid. Name must not be null
Person no 2 is not valid. Age must be greater than zero
Person no 3 is  valid. 

かなりきれいですね。

于 2013-10-17T12:58:41.770 に答える
2

何を使っているかわかりません。私はSpring MVCプロジェクトに慣れています。これらに対して、JSR-303 バリデーターを使用できます。これは、ObjectErros オブジェクトをオブジェクトのすべてのエラーで埋めます。

spring を使用している場合は、SmartValidator を探してみてください。注入後、次のことができます。

BeanPropertyErrors br = new BeanPropertyErros();
validator.validate(object,br);

Spring を使用していない場合は、JSR-303 実装を探してみてください。

それを使用すると、検証するクラスのフィールドで @NotEmpty、@NotNull、@Min、@Length を使用できます。

于 2013-10-10T01:02:42.163 に答える