I'ven been reading about the Abstract Factory pattern but even though I understand it, I don't know when to use it. The definition of the pattern says that it is used to abstract the object instantiation but its not very clear to me as of why should I need to do that, why should I care about object instantiation and why (or when) is it important to abstract it.
4 Answers
The chief benefit of the pattern is that it enables clean and re-usable code by decoupling object creation from object usage.
I don't have a C# example handy, unfortunately, but an example use case I've had this week was designing an object that needs to open a socket. This is on Android, where certain versions incorrectly implement SSL/TLS.
To work around this bug, on those versions of Android we have to do some heavy customization of the SSL environment in order to successfully talk to the backend. Using an Abstract Factory allowed us to write the socket client so that it didn't need to know anything about the messy details - it just had a factory to get a socket from.
An example:
// this is pretty gross, but what can you do public class SocketFactorySupplier implements Supplier<SSLSocketFactory> { @Override public SSLSocketFactory get() { if (androidVersion >= 2.1 && androidVersion <= 2.6) { return createShiftyWorkaround(); } else { return getDefaultSocketFactory(); } } // here are ~500 lines of SSL code } ... public class NetworkClient { private final Supplier<SSLSocketFactory> supplier; private Socket socket; public NetworkClient(Supplier<SSLSocketFactory> supplier) { this.supplier = supplier; } public void connect() { socket = supplier.get().createSocket(); socket.connect(); // code that doesn't care about SSL at all and is simpler for it } } This obviously isn't real code, but it demonstrates the main benefits of the Abstract Factory pattern:
- the
NetworkClientcode is cleaner because it doesn't care about how sockets are built - the client can easily be tested by supplying mock sockets, isolating it from the network
- the SSL logic can be reused in other classes that need sockets
- etc.
Comments
Let's pretend you are writing an application that needs to talk to a database. You could have a Database class that acts like a factory to create commands with a Database.CreateCommand method. If you need to use different database engines you would need a different implementation of Database for each engine.
You may not know at runtime which command factory you will need, so you create a DatabaseManager class that has DatabaseManager.GetDatabase(databaseType) function that returns a specific kind of DataBase. DatabaseType could come from a configuration file so that it could be easily changed.
In this example each Database would be a regular Factory, while DatabaseManager would be an Abstract Factory`. It is a factory that creates other factories.
So you could in essence do something like this:
Dim sqlCommand as ICommand = DatabaseManager.GetDatabase("MsSQL").CreateCommand or
Dim oracleCommand as ICommand = DatabaseManager.GetDatabase("Oracle").CreateCommand Comments
The Abstract Factory pattern is one that doesn't make much sense with academic examples. I prefer to think of design patterns based not on how they are implemented, but rather the problem that they are meant to solve. In this case, the Abstract Factory pattern is meant for a situation where you have a factory that will need to change based on information that isn't available at compile-time. To state in a different way, it is helpful when you want your factory to create a different type of product based on information that only becomes available when you run it. The differences in functionality are contained in the factory products themselves rather than the code that consumes them.
The best academic example I've seen is in unit testing. When you're testing the consumers of your factory's products, you often don't want the full heavyweight functionality of the products, but instead bare-bones filler so you can isolate the logic of the consumer. With the factory pattern, this doesn't work. With the abstract factory pattern, it's trivial. Instead of having a single factory that is always used, you have 2 factories- one that produces dummy objects and one that produces real products. The dummy factory is used when the unit tests run, and the real factory is used when run normally.
Another good example is cross-platform support. You may want your factory to produce different products depending on whether you're running on OSX, Windows, Linux, IOS, Android, etc. An abstract factory allows you to implement a factory for each operating system, and pick the appropriate one at runtime.
This are extremely simple use case. The extra layer of abstraction allows you to apply a wide variety of OO design strategies to the factory hierarchy, the most obvious being inheritance. I've found Abstract Factories to be particularly powerful when combined with dependency injection, whether you're doing it within a managed container like Unity or by hand (which is still a good design practice).
Comments
The main advantage of Factories, is that they allow the calling object to remain simple, and not have to change when new functionality is added to the application.
Suppose you have a simple Shopping Cart UI, and your company has one product. This very concrete code will work fine at first.
public class MyShoppingCartUI() { private List<IProduct> _productsInCart = new List<IProduct>(); public void ClickAddProductButton() { IProduct product = new ProductOne(); _productsInCart.Add(product); } } But when your company adds a new product, you will have to change your UI code to directly reference the new Product. So you have to change the UI code to this:
public class MyShoppingCartUI() { private List<IProduct> _productsInCart = new List<IProduct>(); public void ClickAddProductOneButton() { IProduct product = new ProductOne(); _productsInCart.Add(product); } public void ClickAddProductTwoButton() { IProduct product = new ProductTwo(); _productsInCart.Add(product); } } As you can see, every time you have a new product, you have to add more code and your UI class gets bigger and bigger. Why should your Shopping Cart UI depend on what products are available?
This can be solved with a factory. Here is a decoupled code sample:
public class ProductFactory() { public IProduct Create(string productName) { if (productName == "Product1") return new ProductOne(); else if (productName == "Product2") return new ProductTwo(); } } public class MyShoppingCartUI() { private ProductFactory _factory = new ProductFactory(); private List<IProduct> _productsInCart = new List<IProduct>(); public void AddItem(string productName) { IProduct product = _factory.Create(productName); _productsInCart.Add(product); } } This way, no matter how many products you add, you never have to change the UI code, since it does not care what products you make. You can bind all your controls with a List of the Product Names or IDs and the Factory will give you those objects.
Another advantage is that the rest of application can also use the Factory to get it's Product objects, so you won't have to separately maintain code that creates the Product Objects. Just 1-2 new lines in the factory class will cover you forever, no matter how big your Application gets.
2 Comments
Factory, but RaulMonteroC specifically asked about Abstract Factories, which are a bit different.
Abstract Factorypattern and not just the standardFactorypattern? They are two different but related things.