0

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 line1, 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.

Community
  • 1
  • 1
Mark Allison
  • 6,838
  • 33
  • 102
  • 151

5 Answers5

2

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-

Eric Brown - Cal
  • 14,135
  • 12
  • 58
  • 97
1

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.

flq
  • 22,247
  • 8
  • 55
  • 77
0

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;
        }
    }       
}
0

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.

SQLMason
  • 3,275
  • 1
  • 30
  • 40
  • OK thanks, yes makes sense. Any thoughts on the "ownership" of an Address by a Person? – Mark Allison May 26 '11 at 16:25
  • What if a two people have the same address? You'd have a reference object to the same instance... if you noticed that the ZIP changed then it would change for all the people associated with the address. You don't want parents to own children. Children are their own objects which could eventually have children of their own (maybe I made that a metaphor). – SQLMason May 26 '11 at 16:55
  • Sorry, I didn't understand what you were asking. As Eric mentioned, the Person would have a collection of addresses. I didn't notice that it was missing in your object. – SQLMason May 26 '11 at 16:57
  • I agree with Dan H above, in that an Address should know nothing about saving it's data. When you give your address to your bank, do they ask you to capture it on their system? – ProfK Nov 06 '11 at 09:35
0

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.

Dan H
  • 1,828
  • 2
  • 21
  • 38