Use ValueObjects Not objects.
In the registration case, you can enter an object of value UserName. Create a Username object during registration. Embed validation in the UserName constructor.
See question and presentation for more details.
Edit1:
1. How to handle cases where different validation rules apply to different contexts.
For example: the username should not contain numbers for a specific type of member, but is it necessary for other types of members?
Perhaps different factory methods can do this. e.g. UserName.forGoldenCardMember (...) or UserName.forPlainMember (...). Or do MemberType (possibly hierachy) to check for UserName.
Another alternative solution is to use AggregateFactory (AccountFactory in this case).
2. Am I creating the only place to place the verification code? I read online about two points of view: an object should always be valid, and not always. Both present good arguments, but any other approach?
I prefer a valid approach personally. Passing an invalid value object harms encapsulabilty.
Edit2:
require a) a context-based validation business rule (different username rules for member types) b) continue to validate all business rules, even if one of them fails
Adhere to the principle of single responsibility with the help of Value Object (MemberType in this case). AggregateFactory can be introduced to simplify the application level (coarser granularity).
class AccoutFactory { Account registerWith(Username username, MemberType type, ....) { List<String> errors = new ArrayList<String>(); errors.addAll(type.listErrorsWith(username)); errors.add(
Edit3: For questions in the comments
a) Should the name object be the one who has a method that returns an error, for example listErrorsWith ()? After all, does this username have different rules for different types of members?
We could check this question from a different perspective: MemberTypes have different rules for the username. This can replace if / else in the Username.listErrosWith (String, MemeberType) file with polymorphism;
b) If we have a method in MemberType, knowledge will not be encapsulated in Username. In addition, we say that the username is always valid.
We could determine the correct username without MemberType rules. Assuming hippoom@stackoverflow.com is a valid username, it is a good candidate for a GoldenCard member, but not a SilverCard member.
c) I still donβt see how a check is being performed that returns a list of errors without getting a list from the exception thrown by the constructor or the static method. Both do not look perfect IMHO.
Yes, the signature of the ListErrorsWith (): List is as follows: I would prefer to use validate (username) with no return value (throw exception on failure). But this will force the ciltor to catch every validation step in order to run the test immediately.