Note
While this is a book about object-oriented programming, a function really is fine. It's common, idiomatic Python.
We can always rewrite a function to be a proper callable object if the need arises. From a callable object, we can refactor it into a class hierarchy for our factories. We'll look at callable objects in Chapter 5, Using Callables and Contexts.
The advantage of class definitions in general is to achieve code reuse via inheritance. The function of a factory class is to wrap some target class hierarchy and the complexities of object construction. If we have a factory class, we can add subclasses to the factory class when extending the target class hierarchy. This gives us polymorphic factory classes; the different factory class definitions have the same method signatures and can be used interchangeably.
This class-level polymorphism can be very helpful with statically compiled languages such as Java or C++. The compiler can resolve the details of the class and methods when generating code.
If the alternative factory definitions don't actually reuse any code, then a class hierarchy won't be helpful in Python. We can simply use functions that have the same signatures.
The following is a factory function for our various Card
subclasses:
def card( rank, suit ): if rank == 1: return AceCard( 'A', suit ) elif 2 <= rank < 11: return NumberCard( str(rank), suit ) elif 11 <= rank < 14: name = { 11: 'J', 12: 'Q', 13: 'K' }[rank] return FaceCard( name, suit ) else: raise Exception( "Rank out of range" )
This function builds a Card
class from a numeric rank
number and a suit
object. We can now build cards more simply. We've encapsulated the construction issues into a single factory function, allowing an application to be built without knowing precisely how the class hierarchy and polymorphic design works.
The following is an example of how we can build a deck with this factory function:
deck = [card(rank, suit) for rank in range(1,14) for suit in (Club, Diamond, Heart, Spade)]
This enumerates all the ranks and suits to create a complete deck of 52 cards.