Spoke with a friend of mine and I think he helped me understand more.
userBean.cfc - A transient object, stored into a persistent scope (SESSION) which has properties as well as accessor methods (getters) and mutator methods (setters) for the properties. If a userBean has 3 properties: lastName, firstName and age, then, if it is a read-only bean, it will have getFirstName(), getLastName() and getAge() accessors, but if it is a Read/Write bean, it will have those methods and setFirstName(), setLastName() and setAge(). The userBean object is only aware of itself, and if read-only, usually sets its properties when it is inited.
userGateway.cfc - A singleton object, stored into a persistent scope (APPLICATION) which provides method functionality for a singular userBean objects. userBeans are passed to the gateway as well, along with a method, such as: userGateway.getReverseName( userBeanObject ). Since CF passes objects by reference, the getReverseName can pull getLastName() and getFirstName() from the userBean object passed in and return back a string to the caller of the name in reverse orded, (lastName, firstName).
userService.cfc - A singleton object, stored into a persistent scope (APPLICATION), which provides method functionality for multiple userBean objects. The userService could have a method like killNonAdminUserSessions() where it would coordinate with CF service objects in iterating over sessions for the current application, and since the userBean is stored into the session scope, it can get identifiers for those, and then use the gateway run a killUserSession() method over each userBean object the service found.
So a userBean represents a single instance of data and its properties. The userGateway represents functionality that can be performed on single data instances. And the userService represents functionality that can be performed on multiple data instances, many times, sending userBean objects to a userGateway object iteratively.
.....Did I get it right?
The bean part I think you got mostly right. The method getReverseName() would actually be on the bean not the gateway, and any other methods that would calculate values based on properties of the bean (e.g. a getBirthYear() method to subtract the age from the current year).
Generally, gateways are singletons used to get data from an external store, be that a database, a web service, a file, or anything else. It can return multiple records, so if you are populating beans with the data it returns, you might actually return an array of beans. Related to gateways are Data Access Objects (DAOs), which are singletons that are used to perform CRUD operations (create, read, update, delete) on a single record (or bean). Sometimes, developers will combine DAO and gateway methods into a single object.
The service objects, as I understand them, are an abstraction layer that "hides" the gateways/DAOs/beans (your model) and provides a simpler layer of interaction with the rest of your application.
I'm still trying to understand the OOP process myself, so if I've gotten any of this wrong, hopefully someone else will jump in and correct me.
Thanks Carl! You're always good for some clarification!
So a bean is comprised of properties. And aside from getting/setting those properties, they are also responsible for any functionality based on those properties. That makes sense. Might as well keep all property-related methods in the same object. I hear people constantly talk about the singularity of a bean. They keep saying "It is 1 record of data" (but this keeps putting me in the mindset of database tables/fields). If I have a user bean, and he has a lastName, firstName and age property, he is simply contains data on a singular entity. Correct?
And gateways are used to access external data, you say, right? The most common of course is databases. So I'm trying to formulate an example. A userGateway object woud have methods that (if combined with the DAO functionality, would include CRUD-related taskes on the user, but aside from dealing with just 1 user bean, they support the ability to address multiple, right? So for example, if I wanted to create a single user bean for all users, I would access this userGateway object, call a method like getAllUsers(), it would contain the data source and then it would create each user bean by sending data to their init() method, correct?
And because this methodology inside a bean and gateway may include many functions, a lot of which are private and just used to encapsulate tasks and be called privately, a service layer is the "frontend" to the gateway/dao + bean "backend", providing methods that simplify the tasks. For example.
1. Call userService.getUserBean( 2 )
2. The userService contacts the userGateway's readBean( id ) method which hits the databases and returns a query of 1 singular row of data.
3. The userGateway then takes that data and inits a singular user bean based off the data by calling the user.cfc and passing in init() data.
4. The userGateway then sends that user bean back to the userService which returns the bean back to the caller.
Do I have that down?
That looks right to me. I am hoping someone with more OOP experience can jump in and confirm, though.
I had spoke to Adam Tuttle, and one of my core problems was that I wanted to OOP-ify everything, lol.
For example, I have a structure that's stored into the SESSION scope and it holds data about the user. So naturally, I start building a userBean and going through this whole process and he noted that objects should be considered very carefully if stored into persistent scopes like SESSION, APPLICATION, etc. Because he said that they are not that memory-efficient, and if I just get out of hand throwing objects into memory, I'll end up using a ton of memory. His suggestion: just use the structure. Not everything has to be an object.
Of course, now it has me wondering. "Well, then what DOES warrant turning into an object?"
I just finished reading Matt Gifford's OOP in ColdFusion book, and it did a great job in teaching principles, but I'm still pondering the above question.
My personal opinion is that if you are using the bean to only hold values and are not adding methods to perform manipulation of those somewhat static values, and you are not going to be performing CRUD operations on the bean (other than Read), then a structure is appropriate for that use case (and less work to code). I don't think everyone should rush to "OBJECT ALL THE THINGS!" . Use OOP when it makes sense. I'm still trying to get there myself, so I feel your pain trying to sort all this out.
True enough, Carl. Glad to see others on the same road. Hey, get out of my lane!
If there is anything I've learned while developing my own framework, it's that it is ALWAYS worth your time to learn about a subject matter to the point of comprehension vs. taking on the task of "doing it as you learn it". The latter is something I've done too many times, only to have to refactor my code repeatedly. But the former is hard to do, since the subject matter is so in-depth, and you'd really need someone who'se "Been there, done that" to bounce the myriad of questions off of in order to make sure I am comprehending this properly.
I love those Eureka moments, and I feel I'm inching forward to this one.
That "Learn CF in a Week" website stated that I need to avoid the 5:1 in syndrome of feeling that a DAO, Service, Gateway, Bean and Controller need to be made for everything. They suggest merging the DAO, Gateway and Service, where possible. I think the guidelines you just listed make a lot of sense.