Separating responsibilities of Models / VOs in a hierarchical structure?

Maciek's Avatar

Maciek

May 18, 2010 @ 05:33 PM

I looked at Joel's AddressBook application mentioned in this discussion. This reinforces what I felt should be the separation between model and VOs (I'd been struggling with this as it's not clear in a lot of simpler examples), but it's not clear how to scale this up to a more complex underlying model.

E.g., suppose instead of a simple address book, you need to manage organizational charts across several different subsidiaries of a megacorporation. So, you still have your Contact at the lowest level, but now you have Department (a list of Contacts, department head--a Contact--and department name), and Subsidiary (with a list of Departments, a President--also a Contact--and a subsidiary name). Any thoughts on how to approach something like this?

  1. 1 Posted by Jonny Reeves on May 19, 2010 @ 09:31 AM

    Jonny Reeves's Avatar

    Hi Maciek,

    The applications I work on often comprise of a fairly complex [Object Graph] (http://en.wikipedia.org/wiki/Object_graph). I will always start out by building the heirarchy using Plain Old Value Objects, so in the simplest example I might use an Address object to represent a Contact's Address in a Contact Manager app:

    public class Contact {
        public var firstName : String;
        public var lastName : String;
        public var address : Address = new Address();
    }
    
    public class Address {
        public var houseNumber : String;   // Could be 3A
        public var houseName : String;
        public var street : String;
    }
    

    I will then, depending on just how complex the Object Graph is, create a top level Model class (Proxy) which shields it from the interactions of the Framework. My Model object often becomes fairly intimate with the Object Graph, but that doesn't bother me too much as it's the single point of contact.

    public class ContactsModel {
        private var _contacts : Vector.<Contact>;
    
        public function set contacts(contacts : Vector.<Contact>) : void {
            _contacts = contacts;
            dispatch(new ContactsUpdatedEvent(ContactsUpdatedEvent.UPDATED, contacts));
        }
    
        /**
         * This is just an example of how the Model shields the structure of the Value Objects from the application, I appreciate it's
         * not a very good real world example!
        */
        public function getAddressFor(lastName : String)  : Address {
            const contact : Contact = findContactWithLastName(lastName);
            if (contact) {
                return contact.address;
            } else {
                throw new ArgumentError("No contact with last name: " + lastName);
            }
        }
    
        private function findContactWithLastName(lastName : String) : Contact {
            var result : Contact;
            for each (var contact : Contact in _contacts) {
                if (contact.lastName == lastName) {
                    result = contact;
                    break;
                }
            }
            return result;
        }
    }
    

    Jonny.

  2. 2 Posted by Maciek on May 19, 2010 @ 10:47 PM

    Maciek's Avatar

    Thanks, Jonny. This seems like it could get pretty unwieldy if you go a few more levels deep. Any thoughts on handling that?

  3. 3 Posted by Maciek on May 27, 2010 @ 10:16 PM

    Maciek's Avatar

    Okay, let me go back to this and try a more specific example:

    Company {
      public var ceo:Employee;
      public var departments:ArrayCollection /* of Department */;
    }
    Department {
      public var head:Employee;
      public var employees:ArrayCollection /* of Employee */;
    }
    Employee {
      public var firstName:String;
      public var lastName:String;
      public var address:Address;
    }
    Address {
      public var city:String;
      public var state:String;
      public var streetAddress:String;
    }
    

    I could have a CompanyModel that deals with everything from Company to Address, but that seems pretty messy. Alternately, I could have a parallel hierarchy for these manager / "proxy" objects along with my VOs, but Commands that act on just part of the graph would be awkward, and it's not clear how to notify the Mediators / PMs that a particular object somewhere in the graph has changed. It seems like you can sort of work around this with the concept of a "current VO" in each Model object, but this does not seem like the most elegant solution, especially if you have multiple "current" objects.

  4. 4 Posted by Mark A. on Jul 13, 2010 @ 02:05 PM

    Mark A.'s Avatar

    Someone has an idea on that one. I see it like Maciek - when the hierarchie gets deeper interface functions like getPersonWithName(); cannot be the right solution. Mh, maybe one could invent an object that gets puhed down the hierarchie and every "layer" tests that object on a particular attribute and if so returns something or pushes it deeper into the hierarchie? -just thoughts-

  5. 5 Posted by Mark A. on Jul 13, 2010 @ 02:08 PM

    Mark A.'s Avatar

    Or you flaten the hierarchy and work with IDs. You have arrays of persons and arrays of departments and they share a key like in relative databases.

  6. Stray closed this discussion on Feb 12, 2011 @ 01:25 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac