One of the goals in our designs has been separation of data layer, business layer, and presentation layer. We have Data Access Objects (DAO's) to access data stores (we don't care if the data comes from a relational database, an XML document, flat file, whatever). Value Objects (VO's) are used to hold the data. Conceptually, they represent a single row from a query and are created and set by DAO's. Other than the Setters and Getters, the VO's do not contain any business logic, nor do they have any Data access logic in them. All of this has been presented as back ground into my real question (finally). Where would (should?) one model relationships between VO's? I think this is really business logic, but could be persuaded (reluctantly) to do this at the VO level. For example, if you have a sales order. Conceptually, an order consists of header information (Customer ID, shipping info, etc.) and a number of detail rows, one for each item purchased. This is a very basic one to many relationship. Where is this relationship expressed in code? The sales order could have come from a relational database, an XML document, a flat file, a spreadsheet, etc. Plus we do not want an implementation that relies on a specific data access technology or data source. One approach would be to embedd a container object in the header VO and then load it with references to the detail VO's, and have a reference on the detail VO's that point to the header. Another would be to have some sort of relationship object (RO?) that would perform and manage the mapping functions to express the relationship. There are other approaches that likewise could be used. I guess I am trying to see how others handle this and what some of the options are. I have not found anything in any of the patterns books that covers this. Thanks in advance!
I model relationships in the VOs. I don't think of "An Invoices consists of Invoice Items" as business logic; this is something that should be inherant in the data structure (through the use of Foreign keys and the such). Business logic is something like "The amount of the invoice should total the sum of the Invoice Item Amounts" (ususal logic) and "The amount of the invoice should equal the average value of the invoice items." (bizzare logic ) I suppose that you could use Relationship Objects to model the relationships, but my VOs contain some sort of Collection (usually List) to express teh relationship and the appropriate methods to maintain the relationship (setting keys, etc.) You might get more responses if this were posted in the Patterns forum. I moseyed on over to there and discovered that they are looking for things to talk about [ April 15, 2003: Message edited by: Joel McNary ]
Piscis Babelis est parvus, flavus, et hiridicus, et est probabiliter insolitissima raritas in toto mundo.
I totally agree with Joel. I would just like to add that I consider Value Objects to be Presentation Layer objects, and so I only put relationships that are required in the Presentation Layer into the Value Objects. Which may be over and beyond what's required in the Business Layer. For example in the case of the Order and Order Line Items relationship, I may use an aggregate Entity Bean to model that relationship in the Business Layer. But, say if the screen displays an Order, Order Line Items and some Customer information, I might put all of that into the Value Object, of course, using lazy loading techniques. I would love to hear what other people think about this strategy. Thanks.
There may be Value objects that the business layer uses to communicate with the presentation layer. These may or may not be passed on from the data layer. We are considering a category of VO's that are only used between the business layer and the presentation layer to be called Transfer Objects to distinguish them from traditional VO's. (The business layer does not know what the presentation layer, or client is. It could be a web page, a web service, an XML document, or even another application.) In the example of an invoice, since each detail line of the invoice is itself a VO, and can be manipulated independantly of the header data (and in many instances are, for example totaling an order does not require the header at all.) Since header data can stand alone, and detail data can also stand alone, they are each represented by VO's. I guess it would make sense to have an invoice VO that would model the relationship between them, with an embedded header VO and a container with all the detail VO's The difficulty (at least conceptually) is that modeling the order structure within a VO seems to violate the purity of the object. We only allow getters, setters, and a to string method in a VO. As far as the relationship between a head and detail being business logic, while it is somewhat subjective, it really is a business model that drives this relationship. I have worked with transactional systems that were designed such that an 'order' was a single record in which the header and detail information were together. This system only allowed a single item on a transaction. In this case the business logic dictated a single object per order, whereas our business logic dictates multiple objects per order in an hierarchy. In fact, if you really want to get a feel for the relationship, here's a quick overview (still omitting some information for clarity): * Order header (1 per order) * Order detail (1..N per order) * inventory allocation (1..N per detail) * Allocation packaging (1..N per alloc) * Order total (1 per order) * Order Packaging (crosses multiple orders & details) It gets complex fairly quickly. Hopefully this helps to understand where I am coming from.
The difficulty (at least conceptually) is that modeling the order structure within a VO seems to violate the purity of the object. We only allow getters, setters, and a to string method in a VO.
Your "purity of object" manifest makes it impossible to implement relationships in your objects! Unless your getter can get a Collection or an array? There is really nothing difficult about implementing relationships in your objects if you are prepared to use Collections and arrays. Can you explain the rationale behind using only getters and setters?
Ok, let me try this: Since the order detail data can stand alone. i.e. certain analysis, etc, does not require that we even look at header data. So there is a VO that represents a detail line. Likewise, there is certain processing that only involves header data. There is a VO that represents a header record. Since a header is a unique entity and does correlate to a object in the database, it is in a VO. A detail line is a unique entity and also correlates to an object in the database. However, the concept of invoice, or sales order is expressed as a relationship between objects. In fact, a sales order is conceptually nothing more than a container with an explicit hierarchy. This hierarcy is based upon business rules. (which of course are subject to change) I think I've answered my own question. There will be an invoice object that will enforce the relationship between all the VO's that comprise a sales order. It won't necessarily be a VO, and it will definately live at the business layer. It can be used to comunicate with the presentation (client) layer. I'll probably implement as an interface, with a factory to instantiate to isolate the invoice from changes in requirements. (also allows for credits, transfers, local buys, etc.) This is called collaboration with remote participants. Thanks!
joke time: What is brown and sticky? ... ... ... A stick! Use it to beat this tiny ad!
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop