http://qualityisspeed.blogspot.com/2015/04/dependency-elimination-example-primitive-support.html
Primitive Support:
- A primitive type (int, string, etc) representing a domain concept (megabytes, phone number, etc).
- A helper class that does something meaningful with that primitive (e.g. MegabyteConverter or PhoneNumberParser or FooHelper).
A Simple Example: E-mail Address Validation
public class UserSignup
{
public void Signup(string emailAddress, string password)
{
if (!EmailHelper.IsValidEmail(emailAddress))
throw new InvalidEmailAddressException(emailAddress);
// Do your signup magics
}
}
public class EmailHelper
{
public static bool IsValidEmail(string emailAddress)
{
// do your fancy string magics
}
}
Sligthly Changed, But Better More Or Less:
public class UserSignup
{
private IEmailValidator emailValidator;
public UserSignup(IEmailValidator emailValidator)
{
this.emailValidator = emailValidator;
}
public void Signup(string emailAddress, string password)
{
emailValidator.Validate(emailAddress);
// Do your signup magics
}
}
public interface IEmailValidator
{
void Validate(string emailAddress);
}
public class EmailValidator : IEmailValidator
{
public void Validate(string emailAddress)
{
if (!IsValid(emailAddress))
throw new InvalidEmailAddressException(emailAddress);
}
private static bool IsValid(string emailAddress)
{
// do your fancy string magics
}
}
There is still a cohesion problem: Email address validation is still a concern of UserSignup, and the validation implementation lives in its own EmailValidator world.
Kill the Primitive:
public class UserSignup
{
public void Signup(EmailAddress emailAddress, string password)
{
// Do your signup magics
}
}
public class EmailAddress
{
private string value;
public EmailAddress(string value)
{
if (!IsValid(value))
throw new InvalidEmailAddressException(value);
this.value = value
}
public static bool IsValid(string emailAddress)
{
// do your fancy string magics
}
}
- We've completely separated the concerns. UserSignup has no validation calls or implementations. It just uses an EmailAddress like it should.
- We've improved cohesion. E-maily things live on EmailAddress. UserSignupy things live on UserSignup. No overlap.
- EmailAddress validation is now a compile-time concern. You can't make a bad one, so type-checking will guarantee that the thing you pass in is valid.