Define an interface for creating an object, but let subclasses decide which class to instantiate.
Factory Method defines an interface for creating an object but lets subclasses decide which class to instantiate. Rather than calling new directly, you call a factory method that subclasses override to produce the right product type.
This pattern promotes loose coupling by eliminating the need to bind application-specific classes into your code — the code only deals with the product interface.
createTransport() method. A road logistics subclass returns a Truck; a sea logistics subclass returns a Ship. The high-level shipping logic stays the same — only the transport creation differs.Imagine you're building a UI library. You have a Dialog class that creates buttons. On Windows you need WindowsButton; on Mac you need MacButton. Hardcoding new WindowsButton() in Dialog couples it to a specific platform and makes extension painful.
You need a way to say "create a button" without specifying exactly which kind — letting platform-specific subclasses decide the concrete type.
createProduct(). May contain core business logic that calls the factory method.createProduct() to return an instance of a specific ConcreteProduct.// Product interface public interface Button { void render(); void onClick(); } // Concrete Products public class WindowsButton implements Button { public void render() { System.out.println("Rendering Windows button"); } public void onClick() { System.out.println("Windows click handler"); } } public class HTMLButton implements Button { public void render() { System.out.println("Rendering HTML button"); } public void onClick() { System.out.println("HTML click handler"); } } // Creator — declares factory method public abstract class Dialog { // The factory method — subclasses must implement public abstract Button createButton(); // Uses the factory method — works with any Button public void renderDialog() { Button btn = createButton(); // polymorphic creation btn.render(); btn.onClick(); } } // Concrete Creators public class WindowsDialog extends Dialog { public Button createButton() { return new WindowsButton(); } } public class WebDialog extends Dialog { public Button createButton() { return new HTMLButton(); } } // Client — works with Dialog abstraction, unaware of concrete type public class Application { private static Dialog dialog; public static void main(String[] args) { String os = System.getProperty("os.name"); if (os.contains("Windows")) { dialog = new WindowsDialog(); } else { dialog = new WebDialog(); } dialog.renderDialog(); // same call, different result } }
java.util.Calendar.getInstance() — returns locale-specific Calendar subclassjava.util.Iterator — Collection subclasses implement their own iterator factoriesFactoryBean — creates beans via factory method patternDriverManager.getConnection() — returns driver-specific connectionTestCase — framework calls overridden test method factoriesnew WindowsButton() instead of dialog.createButton(), defeating the abstractionButton interface — never WindowsButton. Code reviews and architecture tests (ArchUnit) can enforce this// ❌ BREAKING — client bypasses factory, couples to concrete class Button btn = new WindowsButton(); // direct instantiation defeats the pattern // ✅ FIX — restrict constructor visibility class WindowsButton implements Button { // package-private — only WindowsDialog (same package) can instantiate WindowsButton() {} public void render() { /* ... */ } public void onClick() { /* ... */ } } // ❌ BREAKING — ConcreteCreator returns wrong type silently public class BuggyDialog extends Dialog { public Button createButton() { return new HTMLButton(); // wrong platform — breaks visual consistency } } // ✅ FIX — ArchUnit test enforces factory usage (no direct instantiation) // noClasses().that().resideInPackage("..client..") // .should().accessClassesThat().resideInPackage("..product.impl..")
createProduct(). ConcreteCreators override it. Client calls the Creator's methods without knowing the concrete product.