In this chapter we look at:
Allows interfaces for creating objects without exposing the object creation logic to the client.
The simple factory pattern is a simplified merger of the abstract factory pattern and the factory method pattern. To implement it all that is required is a single class with a method that returns a new created object. The method generally takes either a string or enum parameter that is then used in a switch statement to choose which object to create.
A frequent criticism on simple factory pattern is, that it does not adhere to the open/closed principle. This principle states, that software entities should be open for extension, but closed for modification. In other words it should be possible to add new behavior to a class through inheritance or composition, without having to modify the class itself. Simple factory pattern accesses all the classes it can construct through a switch statement - every time a class is added to the factory, the switch statement has to be updated.
When patterns are read as a set of rules and restrictions, as opposed to guidelines, the resulting code will gain all the complexity from the unused layers of abstraction, while gaining none of the benefits. It is recommended to create interfaces and abstract base classes only after it is clear that they are necessary, instead of starting out with the maximum possible complexity a pattern has to offer. With that in mind the abstract factory pattern implemented in its minimal form is of similar complexity as the simple factory pattern.
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
The abstract factory pattern is often used together with either the factory method or prototype pattern. The actual creation of objects is handled by the other patterns, abstract factory simply creates an additional level of abstraction between the context class requesting objects and creator classes creating the objects.
We can make use of this to define families of objects. As an example in games tiles are often separated into different styles. One dungeon could be an underground catacombs made out of stone blocks and another a dug out mine with moss all over the place. But we know that both of the settings have some kind of floor, wall and a door.
To reuse our code responsible for laying out the dungeons we can extend each of the tile types out of some common parents. Eg CatacombFloor and MineFloor both implement a common parent Floor.
Now we can set up an AbstractTileFactory class, that can make a floor, a wall and a door, without specifying a concrete type for these tiles. The abstract factory could be implemented with factory method pattern, meaning it would define a MakeFloor method, which returns a Floor, a MakeWall method which returns a Wall and so on.
Next we extend the AbstractTileFactory with CatacombsFactory and MineFactory classes. CatacombsFactory make methods will return tiles from the catacombs family and MineFactory returns tiles from the underground mine tiles family. As the dungeon layout code only expects a floor to be some kind of floor tile, then it will be happy with a floor tile coming out from either of the concrete factories.
When patterns are read as a set of rules and restrictions, as opposed to guidelines, the resulting code will gain all the complexity from the unused layers of abstraction, while gaining none of the benefits. It is recommended to create interfaces and abstract base classes only after it is clear that they are necessary, instead of starting out with the maximum possible complexity a pattern has to offer.
Use the Abstract Factory pattern when
Related patterns: