โ Back to Design Patterns
๐ญ
Creational
Factory Method
Defines an interface for creating objects but lets subclasses or a factory function decide which class to instantiate.
The Problem
Client code needs objects but shouldn't be coupled to their concrete classes. Hard-coding `new ConcreteType()` everywhere makes switching implementations painful.
How It Works
- โบDecouples client code from concrete class implementations
- โบOpen/Closed: add new product types without modifying existing code
- โบThe factory encapsulates all knowledge of which class to create
- โบCan return different subclasses based on input parameters
- โบAbstract Factory extends this by creating families of related objects
When to Use
โWhen you don't know ahead of time which class to instantiate
โWhen you want to centralize and control object creation logic
โWhen subclasses should decide what objects to create
โWhen creating objects of different types based on runtime config or environment
Real-World Examples
๐
iOS
UITableView.dequeueReusableCell(withIdentifier:), UICollectionView cell registration
๐ค
Android
ViewModelProvider.Factory, RecyclerView.ViewHolder creation in onCreateViewHolder
๐
Web
React.createElement, document.createElement, Knex query builder
Code Examples
Swift
protocol Notification {
func send(to recipient: String)
}
struct EmailNotification: Notification {
func send(to recipient: String) { print("Email โ \(recipient)") }
}
struct PushNotification: Notification {
func send(to recipient: String) { print("Push โ \(recipient)") }
}
struct SMSNotification: Notification {
func send(to recipient: String) { print("SMS โ \(recipient)") }
}
// Factory function
enum Channel { case email, push, sms }
func makeNotification(for channel: Channel) -> Notification {
switch channel {
case .email: return EmailNotification()
case .push: return PushNotification()
case .sms: return SMSNotification()
}
}
let n = makeNotification(for: .push)
n.send(to: "agus@example.com") // "Push โ agus@example.com"