views:

574

answers:

4

I'm working on wrapping my head around the factory pattern by using it in a simple data storage project in my free time. The idea is to take simple data and save it to a database using a simple factory pattern in VB.NET. I think I have a basic understanding of the pattern itself, however, what I'm struggling with is how to fit the factory classes into the architecture cleanly. I have a standard 3 tier architecture for this project that looks essentially like this:

Presentation

 -Presentation.Common
 -Presentation.DataStorageWebAppName

Business

 -BusinessLayer.Common
 -BusinessLayer.DataStorageAppName

Data

 -DataLayer.Common
 -DataLayer.DataStorageAppName

Common

 -Common
 -Common.DataStorageAppName

Interfaces

 -Interfaces.Common
 -Interfaces.DataStorageAppName

To highlight a particular scenario where I'm having trouble architecting the application, let me give an example. Let's say that in the business layer I create a class in the BusinessLayer.DataStorageAppName DLL called Foo. It has an interface, IFoo, that lives in the Interfaces.DataStorageAppName DLL. To create an instance of the class Foo through it's interface IFoo using a simple factory pattern, right now, I create a Factory class in BusinessLayer.DataStorageAppName and write a shared/static method to do give me an instance through the IFoo interface. Later, as I understand it, I could decide to swap out the object this Factory class returns without having to do much else (in theory).

To get to the point, this works, but what seems funky about it is that I'm now forced into creating several Factory classes: one per DLL essentially, so that I can avoid circular references. Is there a cleaner way to implement these factory classes without resorting to using a 3rd party solution like castle windsor, etc. etc. It seems as though I'm missing a fundamental concept here. It seems as though it should be possible to have a single "repository", if you will, in the architecture that is responsible for handing out object instances.

Thank you in advance!

+1  A: 

I took a simpler approach. I defined an Entity class and I have a factory that produces list of entity (List< Entity >). I tell the factory what types I want to get back, it assumes the type to be the table, the properties to be the columns, generate the sql, get the data, populate a list of new instances of the type.

The factory can also receive an Entity object and use reflection to get update its values in the database.

Now the only thing I need to do is to create the set of Entity classes for a given database, which BTW are the data transfer objects as well.

Otávio Décio
+1  A: 

Is there a reason why your implementation of IFoo and the factory method that returns it cannot live in a separate assembly from the BusinessLayer (and thus you can reference this new assembly from all the client assemblies)? If there is a reason, is it possible that IFoo should be defined in the BusinessLayer as well (and thus not require references to the Interfaces assembly)?

If your interface really does need to be accessible from more than the Business Layer, and the implementation really does rely on the Business Layer then you'll need to look at something a bit more than just the factory method. You could use some of the principles of Inversion of Control / Dependency Injection to get better separation of concerns.

[Edit in response to subsequent answer from O.P.] The Factory Method is not, IMO, sufficient to be considered an IoC approach. What it's best for is encapsulating construction of a specific implementation, to either re-use in multiple places or simply to sweep it under the rug. What's lacking for me is the breaking of dependencies: since your factory method is living in the same assembly as it's being called from, in order to change the concrete type returned, you'd need to recompile. Consider the difference between the following two:

public class FooConsumer1
{
    public void DoStuff()
    {
        IFoo myFoo = new Foo();
        myFoo.Bar();
    }
}

and:

public class FooConsumer2
{
    public void DoStuff()
    {
        IFoo myFoo = FooFactory.getFoo();
        myFoo.Bar();
    }
}

public class FooFactory
{
    public static IFoo GetFoo()
    {
        return new Foo();
    }
}

The advantage of the second is that if you create an IFoo in more than one place, you only have one place to change it when you create a SuperFoo class to replace Foo. Also, there is only one place to put logic if it will decide between two implementations dynamically in some way. Another advantage is that if the constructor is complicated/ugly, or requires some additional code to look up configuration settings or so on, then it hides all that away from the method that is using it.

However, none of those are really (to my mind at least) helping you break the dependencies between this method and the concrete implementation it uses.

Giraffe
A: 

Thanks, guys. These answers have sparked some ideas. I'd like to continue down this path for a bit to see where it leads. Giraffe, I'll answer your questions first, as I feel your post provides more thought into my specific predicament.

I don't have a rule written in stone that says that Foo must live in the BusinessLayer.DataStorageWebAppName assembly. I very well could put it somewhere else, but, where exactly? How would you recommend modifying the architecture so that it remains maintainable and easily usable? The way it stands now, the Foo class lives in BusinessLayer.DataStorageAppName because it's specific to the DataStorageApp itself. It's not intended that it is used in another applications business layer.

I guess my mistake here is that I thought I was using the principles of IoC to provide better separation of implementation and interface. Am I completely off base?

Thanks in advance!

Greg
A: 

It doesn't have to be funky to have several factory classes, if they handle different concerns. I would advice not to use static factory methods, but rather create instances of the factories you use. Then the factories themselves can implement interfaces, and perhaps some of the funkiness goes away.

Øyvind Skaar