I have a class:
public class Person
{
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Email { get; private set; }
public string Telephone { get; private set; }
public Address Address { get; private set; }
public Person(string firstName, string lastName)
{
//do null-checks
FirstName = firstName;
LastName = lastName;
Address = new Address();
}
public void AddOrChangeEmail(string email)
{
//Check if e-mail is a valid e-mail here
Email = email;
}
public void AddOrChangeTelephone(string telephone)
{
//Check if thelephone has correct format and valid symbols
Telephone = telephone;
}
public void AddOrChangeAdress(Address address)
{
Address = address;
}
The properties that are not in the constructor are optional, i.e. the person does not need an e-mail, address or telephone. However, I want to give the user of the class an opportunity to create the object without having to first provide the required information and then afterwards have to find out what methods to use to add the information.
Questions:
- Is it right to create 3 additional overloads to give them that option?
- Should i allow public setters on the optional properties and do the validation there?
- If the person marries and changes last name, do I need additional method to change the last name or should I make this setter public too, and just require them in constructor?
- No.
- Yes
- Make it public.
Assuming you are going to have more code in the AddOrChange
methods such as formatting logic or validation then I'd do the following. Otherwise, I'd completely get rid of the AddOrChange
methods:
public class Person
{
private string _email = string.empty;
private string _telephone = string.empty;
private Address _address = new Address();
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email {
get { return _email }
set { AddOrChangeEmail(value); }
}
public string Telephone {
get { return _telephone;}
set { AddOrChangeTelephone(value); }
}
public Address Address {
get { return _address; }
set { AddOrChangeAddress(value); }
}
public Person(string firstName, string lastName)
{
//do null-checks
FirstName = firstName;
LastName = lastName;
}
private void AddOrChangeEmail(string email)
{
//Check if e-mail is a valid e-mail here
_email = email;
}
private void AddOrChangeTelephone(string telephone)
{
//Check if thelephone has correct format and valid symbols
_telephone = telephone;
}
private void AddOrChangeAddress(Address address)
{
_address = address;
}
}
To work with this class you could do any of the following:
Person p = new Person("Tom", "Jones");
p.Telephone = "9995551111";
or
Person p = new Person("Tom", "Jones") { Telephone = "9995551111", Email="spamme@ms.com" }
AddOrChange
is equivalent to simple property with public setter, thus you don't need those methods.
public class Person
{
public string FirstName { get; private set; }
public string LastName { get; private set; }
public Email Email { get; set; }
public Telephone Telephone { get; set; }
public Address Address { get; set; }
public Person(string firstName, string lastName)
{
//do null-checks
FirstName = firstName;
LastName = lastName;
}
}
If user during person creation want to provide something additional beside required data, she can use class initializers. Also you can add some optional parameters to constructor.
var bob = new Person("Bob", "Uncle") { Address = someAddress };
If its OK for person to relocate, then why not to use public setter for changing address? Of course, you should check if address is valid. Also if relocating is a business process (i.e. you are relocating someone in hotel) then it would be nice to have this operation on domain service (which will verify if destination room is empty and ready).
Allowing to change name is OK. Usually name is not identity for such entities, thus it could change.
Also, I'd introduced value objects for email and telephone. I think it is not person's responsibility to verify if email address valid. Move that to Email class. Same with Phone and Address.
Is lots of add/change methods and constructor overloads a consequence of DDD?
No, lots of updating methods is not consequence of DDD.
Code
Your Person
class can be rewritten to have only 2 updating methods:
class Person
public function Rename(FirstName as Name, LastName as Name) as Person
public function ChangeContacts(
Address as Maybe(of Address),
Phone as Maybe(of Phone),
Mail as Maybe(of MailAddress)) as Person
end class
Rename
method accepts two required parameters of special Name
type. Validation checks for names happen when names are created, not when they are passed into Person
class.
ChangeContacts
method accepts three optional parameters any of which can be absent. Special Maybe
type indicates that they are optional. Special Address
, Phone
and MailAddress
types indicate that these parameters are already valid and there is no need to validate them again in Person
class.
Use case
Person marries and changes last name
Person = Person.
Rename(Person.FirstName, LastNameAfterMarriage)
Person buys new phone number
Person = Person.
ChangeContacts(Person.Address, NewPhoneNumber, Person.Mail)
Person lost phone number
Dim NewPhoneNumber = Maybe.Create(Nothing)
Person = Person.
ChangeContacts(Person.Address, NewPhoneNumber, Person.Mail)
The pattern is to call updating method with old values + some new values.
来源:https://stackoverflow.com/questions/12978381/is-lots-of-add-change-methods-and-constructor-overloads-a-consequence-of-ddd