次のようなクラスがあるとしましょう。
public class CreateUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
ここにあるのは、いくつかの制約があるフィールド「userName」です。そのため、一部の値はOKで、一部はそうではありません。クラスもありますEditUserRequest
。あなたuserName
はユーザー識別子としてユーザーを使用しているので、このフィールドEditUserRequest
を確実に入力します。
public class EditUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
そして確かにあなたはユーザーを削除できるようにしたいです:
public class DeleteUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
これらのクラスはすべて、まったく同様の意味と同様の制約を持つフィールド「userName」を持っています。ある日、sでより多くのシンボルを使用できるようにすることを決定しましたuserName
。したがって、これら3つのクラスすべてを手動で修正する必要があります。
解決策#1
これらすべてのリクエストの基本クラスを作成します。
public abstract AbstractUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
public class CreateUserRequest extends AbstractUserRequest {
... // OK, we have userName here
}
長所:
- これで、制約を一度だけ修正する必要があります
- 新しいタイプのリクエストを作成するのは非常に簡単です。サブクラス
AbstractUserRequest
化するだけで機能します。
短所:
- 他の場所が必要な場合
userName
は、のサブクラスが必要になりますAbstractUserRequest
(例: sのCreateUserGroupRequest
リストが必要userName
です。最初にそれらを検証する必要があります)。 - これを適切にテストする方法が正確にわからない
解決策#2
フィールドのタイプごとに個別のクラスを作成して、「ユーザー名」について話すときに、それが単なるString
、制約されていることを知っているようにしString
ます。
public class UserNameField {
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String value;
...
}
public class CreateUserRequest {
...
private UserNameField userName;
...
}
長所:
- ユーザー名の制約が変更された場合は、一度だけ修正する必要があります
- テストが簡単なシンプルなクラスがあります
短所:
- やり過ぎのように感じる(?)
解決策#3(更新)
Hibernateバリデーターでは制約の構成が可能であるため、制約のグループに名前を付けることができます。
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface UserName {
String message() default "{com.loki2302.constraints.username}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
...
public class CreateUserRequest {
...
@UserName
private final String userName;
...
}
長所:
- シンプルでありながら強力なアプローチ
- 使いやすい(余分な抽象化なし)
- テストが簡単
短所:
- おそらくない?
ここでの一般的なアプローチは何ですか?ソリューション#2は問題ないように見えますか?どうしますか?