At 04:21 PM 12/18/00 +1100, Itai Tavor wrote:
This is how I see it:
- Products Specialist productRack customizableProductRack
- OrderLineItem Specialist lineItemRack lineItemWithGraphicRack
- product.addMeToOrder(): order.addLineItem(product_id=id, add='lineItem')
- custimazable_product.addMeToOrder(): order.addLineItem(product_id=id, add='lineItemWithGraphic')
This should probably be more like: product.addMeToOrder(): item = OrderLineItems.newLineItemFor(self) item.setQuantity(...) etc. order.addLineItem(item) customizable_product.addMeToOrder(): item = OrderLineItems.newLineItemFor(self) item.setGraphic(...) item.setQuantity(...) etc. order.addLineItem(item) This approach makes things more declarative. The product classes can have properties or interfaces that the OrderLineItems specialist can use to decide what kind of line item would serve them best. You can then change your line item assignment rules without necessarily requiring changes to the product classes.
I imagine, then, that the UI for uploading the graphic would be included in product.addMeToOrderForm, using a UI snippet from the OrderLineItemsWithGraphic Specialist. Then I could pass REQUEST on to order.addLineItem and to OrderLineItemsWithGraphic.add, which would then upload the file?
I think you're right about this being an OrderLineItem. A couple of fine points, however... First, I don't think there needs to be an "OrderLineItemsWithGraphic" specialist, since there is nothing else that would talk to it. It's fine in this case to have the line item classes (either with graphic or without) handle their own UI snippets. UI delegation is for when an object needs to display UI for some *other* object than itself, since you can always use class extenders and other techniques to reshape the apparent class of an object retrieved from a specialist. The interface which other objects deal with is "OrderLineItem", and they simply expect a portion of the form to be rendered, and it's okay for the class to handle that. Second, you need to define that interface so that the Order can give the line item constraints on how it does that UI, so it can share the screen and REQUEST with other objects/data that the Order needs. One easy way to do this is to use a namespace parameter, that simply gives the line item a name prefix to use on its fields. Alternatively, you can use the "record" approach, like this: <INPUT TYPE="TEXT" NAME="lineitem1.desiredSize:record:int" VALUE="4"> <INPUT TYPE="FILE" NAME="lineitem1.imageFile:record:file"> ... The resulting REQUEST object from submitting the form will contain a single object, "lineitem1", with "desiredSize" and "imageFile" attributes, so you'll only have to pass a single parameter back to the line item. I've never tried doing a record with a file in it before, so I don't really know how well that works.
Woof... so long. I'd appreciate any comments on this - especially on the question on whether it's better to have a specialized type of OrderLineItem, or to link the standard OrderLineItem to a Product object in case of a standard product, or, in the case of a customizable product, to a new object which stores the graphic and tracks the fabrication of the customized item.
Here's the question... how many behaviors are different in the order line item itself? Are you also using fulfillment line items? If the only difference to the order line item is that it references some additional data, then I'd say a single class would be fine. Most of the behavior probably comes in on the fulfillment line item, yes? Again, you can ask your FulfillmentLineItems specialist to create "newLineItemFor(orderLineItem)" and let it decide what kind of implementation to hand back. In this case, it probably will be a different class, while for the order line items, it may or may not buy you anything. Anyway... remember that Specialists are there to hide implementation decisions like what classes are being used. If you look at the ZPatterns Wiki you'll see references to some of the design patterns which Specialists are an instance of, which will give you some hints as to the many kinds of things they can "hide" for you (and which therefore you should avoid revealing in other code). One of those patterns is that as an object "trader" or "broker", Specialists can be used to create new instances of objects that meet a certain interface, but whose implementation has been selected on the basis of declarative criteria by the requesters.