nuggets as follow
right off the bat, we realize this is not trivial stuff,
"Designing object-oriented software is hard, and designing reusable object-oriented software is even harder."
define a pattern:
"An object that encapsulates access to an external system or resource."
"Pattern: Bridge. Intent: Decouple an abstraction from its implementation so that the two can vary independently."
I agree with Matt Woodward, who says;
"The DAO and the Gateway, from a pattern standpoint, serve exactly the same purpose. They both encapsulate access to a database. The Gateway pattern is used by many ColdFusion developers to contain methods that handle multiple records. The DAO, on the other hand, is used in many ColdFusion applications to deal solely with single records; many ColdFusion DAOs contain only create(), read(), update(), and delete() methods (affectionately referred to as "CRUD")."
This is an excerpt from the mach-II devlopers guide, this version written by Sean CorField and provides great differenciation of the gateway and DAO design patterns and how they should be used. I have struggles to see this, even to explain it, but Sean seems to nail it down very well. Specifically the part about returning query sets from gateways but objects from DAO.
--- Begin quote from the Mach-II Development Guide ---
There are two basic patterns of access to persistent data within most applications:
- aggregated access - reporting, searching, listing multiple rows,
- per-object access - creating, editing, working in depth with a single row (object).
ColdFusion has a great built-in idiom for dealing with the first type of access - the query - which is an efficient way to manipulate (potentially large) sets of data rows retrieved from a database (or other data sources, since you can easily create a query object and populate it with your own data). When you are dealing with aggregated access, it does not make sense to convert every row returned into a fully-encapsulated object (CFC instance) when all you are likely to do with the data is display a few fields with a link to a detail page that will focus on the selected row.
On the other hand, when you are focusing on a single row it usually does make sense to work at the fully-encapsulated object level since you are usually interested in object behavior at that point. This is also the level where you need the standard CRUD (Create, Read, Update, Delete) operations.
Recognizing these two basic patterns, you should design your components accordingly by providing separate components for each pattern. This is best explained through an example:
- If we have a business model object called Order, then we would provide an OrderGateway component for aggregate access and an OrderDAO component for per-object access (or build the per-object access into the Order object - but see below).
- The OrderGateway component would provide methods like findAll(), findWhere(), findByID() and they would all return standard query objects (even findByID() which returns a single row).
- The OrderDAO component would provide CRUD methods like store(), load(), update(), delete() and they would operate on a specific Order object exchanging data via getters/setters on the Order component or via some sort of snapshot of the Order's data, e.g., a bean: the Order component could implement methods like getSnapshot() returning a bean and setSnapshot() taking a bean as an argument - the bean containing the core persistent data for the Order object. Sometimes a more direct data transfer between the business object and the data access object is needed for performance reasons (or because the application can 'trust' the components to exchange less encapsulated data, such as a struct or some opaque data structure e.g., the Memento design pattern). Such optimizations are beyond the scope of this document.
Separating out these operations from the business model object helps it stay persistence-neutral. The gateway components can be optimized for retrieving large record sets, caching etc. The DAO components can be optimized for dirty data updates, pooled object access and so on. Again, the details of these optimizations are beyond the scope of this document but providing for the two distinct patterns of data access will get you started on the right road.
--- End quote from the Mach-II Development Guide ---This wisdom i am paraphrasing from Matt Woodward blog entry, read entire post.
I like knowing that my DAOs deal with CRUD and that's it.
Gateways, on the other hand, are far more nebulous and end up changing much more during application development. I find that I add, remove, and alter methods in my Gateways pretty regularly right up until the application is complete. My DAOs, on the other hand, are built at the outset and they just sit there doing their job.
I also like knowing that when I call methods in my DAOs, they take in an instance of the object with which they are concerned (i.e. the bean) and don't return anything since they're operating directly on the objects passed in. Gateways, by contrast, typically return query objects or, when necessary, collections of beans. Some suggest that if you don't return a collection of objects, we aren't using this pattern "properly." Says who? Fowler? Sun? Maybe in Java the convention is to return a collection of objects. In ColdFusion we have the query that is efficient and easy to use. If all I want to do is loop over a query and display the data, and I don't need to interact with each individual object, why on earth would I make things more complex and less efficient just so I'm better meeting another technology's definition of how a Gateway is supposed to behave? Pure nonsense. When I need to deal with each individual object in an aggregate dataset, I can quite easily return an array of CFCs. When I don't need to do that, I won't bother. Some call that bad programming; I call it practical.
A paraphrase of a Sean Corfield post as response to this post,
"I still maintain that in ColdFusion it makes sense to keep per-object operations separated from aggregate operations because ColdFusion provides a wonderful abstraction called "query" :)
With the rise of ORM frameworks, it makes even more sense to keep "DAO" and "Gateway" separate because the ORMs replace the DAOs completely but only partially replace Gateways, if at all."
No comments:
Post a Comment