How to create a collection that is "owned" by an object?
Following on from this question Good class design by example I have a follow-up one.
I want to create some collections that are owned by other objects. To recap, I have a Person
class and I want the Person
to be able to have one or more Addresses
. So I thought I would create an Address
class and an Addresses
collection. Make sense? Here's my code so far
class Person
{
public Person(int SSN, string firstName, string lastName)
{
this.SSN = SSN;
FirstName = firstName;
LastName = lastName;
}
public int SSN { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Address
{
public Address(string line开发者_高级运维1, string postCode)
{
Line1 = line1;
PostCode = postCode;
}
public int ID { get; set; }
public string Line1 { get; set; }
public string PostCode { get; set; }
}
class Addresses : System.Collections.CollectionBase
{
public int Person { get; set; } // should this be of type Person?
public void Add(Address addy)
{
List.Add(addy);
}
public Address Item(int Index)
{
return (Address)List[Index];
}
public void Remove(int index)
{
List.RemoveAt(index);
}
}
How can I associate many addresses with a Person? I'd like to do something like this in Main
:
Person p = new Person(123,"Marilyn","Manson");
Address a = new Address("Somewhere", "blahblah");
p.Addresses.Add(a);
I then want to be able to save the addresses to a database. Should I do Address.Save()
or Addresses.Save()
(or something else)?
How would I change my code to implement that? Thanks for looking.
If you want the addresses OWNED by a Person, the person Should include a Collection of Addresses
class Person
{
<all the stuff you have>
List<Address> Addresses;
}
Don't forget to new it in the constructor,
Then to add an address you just
Address addressInstance = new Address(){...};
PersonInstance.Addresses.Add( addressInstance );
Cal-
If the Person "owns" addresses, it should expose an Addresses
property. This could be of type ReadonlyCollection<Address>
- no need to create your own collection type.
public Person {
private List<Address> _addresses;
public ReadonlyCollection<Address> Addresses {
get { return _addresses.AsReadOnly(); }
}
public void AddAddress(Address address) {
_addresses.Add(address);
}
}
If you are thinking about good class design, think twice whether every property needs a setter. Maybe you want your object immutable in which case you would want private setters.
That "Save" would follow the "ActiveRecord" pattern. More usual, e.g. when using an ORM like NHibernate, your object crosses some boundary which states that it is stored. In NHibernate this is called a Session which takes care of saving the object according to available information.
Each address should Save(). Your Addresses could Save which would call the save on each of its children.
You'll probably want to have a baseclass which has an enumerable Status such that you'd have New, Modified, UnModified, and Deleted so that you can choose which part of your CRUD will be called. Some people split it up so you'd have booleans, isNew, isModified, isDeleted.
This depends on your architecture...but, for saving the address I would not use the Address object to do it. It's your POCO (Plain old CLR Object) and it shouldn't know about the DAL. Another class should handle CRUD (Creat Read Update Delete) operations and it should be the part of your business layer that interacts with the DAL. Maybe call it AddressComponent.cs? This is a Domain Model Pattern approach.
For the address collection you can just do as flq says and have it as a property...there's really no need to have another object called Addresses.cs unless you need extra logic.
I would use generics to derive List (or any other collection class)
// This class add just an Owner (parent) to the list
public class OwnedList<T> : List<T>
{
public Object Owner { set; get; }
public OwnedList(Object owner)
{
Owner = owner;
}
}
And just pass the the object itself in your class :
class Contact
{
public int Person { get; set; }
private OwnedList<Address> _Addresses;
public OwnedList<Address> Addresses
{
get
{
if (_Addresses == null)
{
_Addresses = new OwnedList<Address>(this);
}
return _Addresses;
}
set
{
_Addresses = value;
_Addresses.Owner = this;
}
}
}
精彩评论