I've been tempted to respond to a lot of the recent threads about factories, as I see a lot of blind following and not a lot of analysis of the solution. Let's start with the problem: our CFCs have external dependencies, there's no way around it. A datasource name (dsn from now on) is great example of such a dependency.
First attempt at solving the problem is directly referencing dsn, e.g. lots of #application.dsn#. We all know this is bad for a number of reasons, the most important being that your CFC is now dependent on some arbitrary variable in an external scope. I might want to repurpose your CFC for an app that doesn't even USE the application scope! Ok, then we move on to "passing in the dsn". This is much better, we've established a way to supply the CFC with its dsn, and now the code is more reusable because we can always create the CFC, pass in a dsn, and be done... the CFC doesn't care about "where" it lives or whether an application scope even exists. Ah but wait, we now made creating the CFC more complex, a necessary burden, but one that can mitigated by several strategies, one of which is the factory pattern. If we make a CFC that's responsible for creating CFCs, then we can move the complexity of creating that CFC into the factory and hide it from the "calling code" (anyone who needs to use/create our CFC). Hmm... but how will the factory know what dsn to pass into the CFCs that it creates? You have to supply that somehow, or maybe the factory goes and reads it from somewhere? Either way, now the factory itself has become more complex to create, which diminuishes its benefits a bit. The factory is still better because you can use it to create multiple types of CFCs, which more than likely have common dependencies like a dsn. However, that's where the benefits of hand-coding factories stop. They are rather inflexible... what if I have a "DAOFactory", which is responsible for creating/configuring 10 different DAOs, and one day I decide that the dsn which DAO #7 needs a different dsn than all the others. You are now going in your factory to add a special case, which is confusing because your factories should be pretty generic. Factories are a good way to hide creational complexity, but they aren't the end-all-be-all. So, we move on to the two new kids on the block... one is known as the Service Locator pattern. The way this works is that your CFCs use the Service Locator to "look up" their dependencies. So when your DAO needs a dsn, it asks the Service Locator for the value. It's actually not typical for a Service Locator to contain simple strings, more likely your DAO obtains a "service" from the service locator, which itself can give the DAO that dsn value - but either way the concept is the same. The problem with implementing the Service Locator pattern in CF is that we don't have static classes, meaning we must supply a real instance of the service locator to each and every CFC that needs to use it. So, instead of supplying your DAOs with a dsn, you supply them with a service locator (or you create a new service locator within every component that needs it). That's why I don't like to use the service locator pattern w/ CF, you are tying all your cfcs to a single instance of something, and you lose the self-documenting nature of describing your CFC's dependencies (meaning having a "dsn" argument to an init() method tells me that this CFC needs a dsn... passing in a service locator hides those dependencies). Lastly we have what's known as Dependency Injection / Inversion of Control. IoC containers are really just factories on steriods. That's why ColdSpring's core class is called the "BeanFactory". It's an all-knowing factory that's externally configurable. Primarily, it resolves your CFC's dependencies by injection, either thru setter methods or contructor arguments. The CFC you wrote that needs a dsn to be passed in can be configured inside the ColdSpring BeanFactory in about 3 lines of xml. You'll never hand-code a factory again. You won't waste time dealing with creational patterns. Your components are easier to test because you don't have to test the component and it's respective factory at the same time. ColdSpring's core is essentially a "factory-framework". I hope that sheds some light on the differences between the more common approaches to assembling a CFC-based model. -Dave Ross ----------------------------------------- CONFIDENTIALITY NOTICE: This email and any attachments may contain confidential information that is protected by law and is for the sole use of the individuals or entities to which it is addressed. If you are not the intended recipient, please notify the sender by replying to this email and destroying all copies of the communication and attachments. Further use, disclosure, copying, distribution of, or reliance upon the contents of this email and attachments is strictly prohibited. To contact Albany Medical Center, or for a copy of our privacy practices, please visit us on the Internet at www.amc.edu. ---------------------------------------------------------- You are subscribed to cfcdev. To unsubscribe, send an email to [email protected] with the words 'unsubscribe cfcdev' as the subject of the email. CFCDev is run by CFCZone (www.cfczone.org) and supported by CFXHosting (www.cfxhosting.com). An archive of the CFCDev list is available at www.mail-archive.com/[email protected]
