Factory Method Interview Deep Dive
Design a logging system where logs can be written to different destinations (File, Database, Cloud). Each log destination requires different initialization and writing logic.
Approach: Create a LoggerFactory as the Creator with createLogger() as the factory method. Subclasses like FileLoggerFactory, DatabaseLoggerFactory, and CloudLoggerFactory create specific logger types. The Logger interface defines log(message). Each concrete logger (FileLogger, DatabaseLogger, CloudLogger) implements destination-specific writing logic.
class LoggerFactory:
abstract createLogger(): Logger
logMessage(message):
logger = createLogger()
logger.log(message)
class FileLoggerFactory extends LoggerFactory:
createLogger(): Logger
return new FileLogger()
Static factory methods (like Integer.valueOf() in Java) are different from Factory Method Pattern. Static factory methods are simple static methods that return instances, not a pattern involving inheritance and subclasses. Use static factory methods when you want named constructors, caching, or returning different subtypes based on parameters, but you do not need the extensibility of Factory Method Pattern.
In a Vending Machine system, different product dispensers (Snack, Beverage, Frozen) require different payment processors and inventory managers. How do you structure this?
Approach: DispenserFactory is the Creator with createDispenser() as the factory method. Each ConcreteDispenserFactory not only creates the dispenser but also injects dependencies like PaymentProcessor and InventoryManager. This combines Factory Method with Dependency Injection (DI), where the factory becomes a poor man's DI container.
First, Parameterized Factory Method: Factory method takes parameters to decide product type within the same subclass. This is a hybrid between Simple Factory and Factory Method. Use when subclasses need slight variations without creating many subclasses.
Second, Default Implementation: Creator provides a default factory method implementation that returns a default product. Subclasses override only when they need different products. This reduces boilerplate when most subclasses use the same product.
Third, Lazy Initialization: Factory method creates the product only when first requested and caches it. This is useful for expensive object creation. However, ensure thread safety if used in concurrent environments.
Factory Method enhances testability by allowing mock products to be injected. Create a TestCreator subclass that overrides factoryMethod() to return mock products. This avoids modifying production code for tests. However, if testability is the only goal, Dependency Injection through constructor/setter might be simpler than creating factory hierarchies.
First, if you see a factory method with a switch statement on type, it defeats the purpose. The whole point is to eliminate conditionals by using polymorphism. Second, if ConcreteCreators do not add any behavior beyond returning a different product, consider using a registry or configuration-based factory instead. Third, if factory hierarchies mirror product hierarchies exactly with no additional logic, the pattern might be over-engineered.