Understand the differences in the motivations:
Suppose you’re building a tool where you’ve objects and a concrete implementation of the interrelations of the objects. Since you foresee variations in the objects, you’ve created an indirection by assigning the responsibility of creating variants of the objects to another object (we call it abstract factory). This abstraction finds strong benefit since you foresee future extensions needing variants of those objects.
Another rather intriguing motivation in this line of thoughts is a case where every-or-none of the objects from the whole group will have a corresponding variant. Based on some conditions, either of the variants will be used and in each case all objects must be of same variant. This might be a bit counter intuitive to understand as we often tend think that - as long as the variants of an object follow a common uniform contract (interface in broader sense), the concrete implementation code should never break. The intriguing fact here is that, not always this is true especially when expected behavior cannot be modeled by a programming contract.
A simple (borrowing the idea from GoF) is any GUI applications say a virtual monitor that emulates look-an-feel of MS or Mac or Fedora OS’s. Here, for example, when all widget objects such as window, button, etc. have MS variant except a scroll-bar that is derived from MAC variant, the purpose of the tool fails badly.
These above cases form the fundamental need of Abstract Factory Pattern.
On the other hand, imagine you’re writing a framework so that many people can built various tools (such as the one in above examples) using your framework. By the very idea of a framework, you don’t need to, albeit you could not use concrete objects in your logic. You rather put some high level contracts between various objects and how they interact. While you (as a framework developer) remain at a very abstract level, each builders of the tool is forced to follow your framework-constructs. However, they (the tool builders) have the freedom to decide what object to be built and how all the objects they create will interact. Unlike the previous case (of Abstract Factory Pattern), you (as framework creator) don’t need to work with concrete objects in this case; and rather can stay at the contract level of the objects. Furthermore, unlike the second part of the previous motivations, you or the tool-builders never have the situations of mixing objects from variants. Here, while framework code remains at contract level, every tool-builder is restricted (by the nature of the case itself) to using their own objects. Object creations in this case is delegated to each implementer and framework providers just provide uniform methods for creating and returning objects. Such methods are inevitable for framework developer to proceed with their code and has a special name called Factory method (Factory Method Pattern for the underlying pattern).
Few Notes:
- If you’re familiar with ‘template method’, then you’d see that factory methods are often invoked from template methods in case of programs pertaining to any form of framework. By contrast, template methods of application-programs are often simple implementation of specific algorithm and void of factory-methods.
- Furthermore, for the completeness of the thoughts, using the framework (mentioned above), when a tool-builder is building a tool, inside each factory method, instead of creating a concrete object, he/she may further delegate the responsibility to an abstract-factory object, provided the tool-builder foresees variations of the concrete objects for future extensions.
Sample Code:
//Part of framework-code
BoardGame {
Board createBoard() //factory method. Default implementation can be provided as well
Piece createPiece() //factory method
startGame(){ //template method
Board borad = createBoard()
Piece piece = createPiece()
initState(board, piece)
}
}
//Part of Tool-builder code
Ludo inherits BoardGame {
Board createBoard(){ //overriding of factory method
//Option A: return new LudoBoard() //Lodu knows object creation
//Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
}
….
}
//Part of Tool-builder code
Chess inherits BoardGame {
Board createBoard(){ //overriding of factory method
//return a Chess board
}
….
}