Given that most of what I do is CRUD, it seems to me quite reasonable that the internal properties stored within the business object should be the field values from the query used to populate it (eventually using field name aliases implemented in the DAO to abstract the object from any ugly names or naming changes in the database itself) . . .
The getters and setters (interfaced via a generic getter and setter) may be a completely different list, with the public gettable/settable attribute name lists (which the getters and setters will respond to) being able to be varied pretty much independently of their internal properties (the only dependency is that it must be possible to calculate the attributes based on the internal properties – you can’t have an Age attribute without a Date of Birth property).
The init() method is fairly simple. It seems reasonable to me that a business object should know its default values, so init will just set the internal (private) properties to the defaults for that business object. This makes it easy to return an object for populating the default values for an "add" form, allowing you to use the same form display code for add and edit – the only difference is whether or not you load the object with data.
If you do want to load information from the database, you call some kind of get method on the service (I may duplicate the interface on the business object, but most of the time I want a record or a list, I want to go to the service object and ask it to give me a loaded business object). The service creates/initializes the object (for now) and then passes it to the DAO. The DAO takes the initialized object and runs a query and then needs to get the 0..n values into the object. For now, given that only the business object should be able to touch its internal private properties, I’m going to put a loadQuery() method onto the base business object, allowing it to set all of the passed properties for 0..n records.
Then what about iterating? Well the absolute minimal interface for a one way iterator is object.first(), object.next() and object.isLast(). You can go to the first record, move iteratively to the next record, and test for the last record to end your loop. Let me code this up and see where we go from there.
FYI, the code is a little ugly right now, but I’ll clean it up and post it over the weekend or on Monday. None of this is anything more than a science experiment right now, but it’ll get posted with some updated comments in case it is of any use.