UI Component Libraries
Create different UI components based on platform or theme.
Ce contenu n’est pas encore disponible dans votre langue.
The Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. It promotes loose coupling by eliminating the need to bind application-specific classes into the code.
The Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. It lets a class defer instantiation to subclasses, enabling greater flexibility in determining which objects need to be created.
UI Component Libraries
Create different UI components based on platform or theme.
Document Processing
Generate different document types (PDF, Word, HTML).
Payment Processing
Handle different payment methods (Credit Card, PayPal, Crypto).
Notification Systems
Send notifications via different channels (Email, SMS, Push).
| Advantages ✅ | Disadvantages ❌ |
|---|---|
| Avoids tight coupling between creator and concrete products. | Can lead to many subclasses. |
| Follows the Single Responsibility Principle. | Code can become more complex. |
| Follows the Open/Closed Principle (open for extension). | May be overkill for simple cases. |
| Easy to introduce new product types. | Requires understanding of inheritance. |
The pattern consists of four main components:
// Product Interfaceinterface Transport {deliver(): string;}
// Concrete Productsclass Truck implements Transport {deliver(): string {return "Delivering by land in a truck";}}
class Ship implements Transport {deliver(): string {return "Delivering by sea in a ship";}}
class Plane implements Transport {deliver(): string {return "Delivering by air in a plane";}}
// Creatorabstract class Logistics {abstract createTransport(): Transport;
planDelivery(): string {const transport = this.createTransport();return transport.deliver();}}
// Concrete Creatorsclass RoadLogistics extends Logistics {createTransport(): Transport {return new Truck();}}
class SeaLogistics extends Logistics {createTransport(): Transport {return new Ship();}}
class AirLogistics extends Logistics {createTransport(): Transport {return new Plane();}}
// Usagefunction clientCode(logistics: Logistics) {console.log(logistics.planDelivery());}
clientCode(new RoadLogistics()); // "Delivering by land in a truck"clientCode(new SeaLogistics()); // "Delivering by sea in a ship"clientCode(new AirLogistics()); // "Delivering by air in a plane"// Product Interfaceinterface Transport {String deliver();}
// Concrete Productsclass Truck implements Transport {public String deliver() {return "Delivering by land in a truck";}}
class Ship implements Transport {public String deliver() {return "Delivering by sea in a ship";}}
// Creatorabstract class Logistics {abstract Transport createTransport();
public String planDelivery() {Transport transport = createTransport();return transport.deliver();}}
// Concrete Creatorsclass RoadLogistics extends Logistics {Transport createTransport() {return new Truck();}}
class SeaLogistics extends Logistics {Transport createTransport() {return new Ship();}}
// UsageLogistics logistics = new RoadLogistics();System.out.println(logistics.planDelivery());// Product Interfaceinterface Transport {public function deliver(): string;}
// Concrete Productsclass Truck implements Transport {public function deliver(): string {return "Delivering by land in a truck";}}
class Ship implements Transport {public function deliver(): string {return "Delivering by sea in a ship";}}
// Creatorabstract class Logistics {abstract public function createTransport(): Transport;
public function planDelivery(): string {$transport = $this->createTransport();return $transport->deliver();}}
// Concrete Creatorsclass RoadLogistics extends Logistics {public function createTransport(): Transport {return new Truck();}}
class SeaLogistics extends Logistics {public function createTransport(): Transport {return new Ship();}}
// Usage$logistics = new RoadLogistics();echo $logistics->planDelivery();// Product Traittrait Transport {fn deliver(&self) -> String;}
// Concrete Productsstruct Truck;impl Transport for Truck {fn deliver(&self) -> String {"Delivering by land in a truck".to_string()}}
struct Ship;impl Transport for Ship {fn deliver(&self) -> String {"Delivering by sea in a ship".to_string()}}
// Creator Traittrait Logistics {fn create_transport(&self) -> Box<dyn Transport>;
fn plan_delivery(&self) -> String {let transport = self.create_transport();transport.deliver()}}
// Concrete Creatorsstruct RoadLogistics;impl Logistics for RoadLogistics {fn create_transport(&self) -> Box<dyn Transport> {Box::new(Truck)}}
struct SeaLogistics;impl Logistics for SeaLogistics {fn create_transport(&self) -> Box<dyn Transport> {Box::new(Ship)}}
// Usagefn main() {let logistics: &dyn Logistics = &RoadLogistics;println!("{}", logistics.plan_delivery());}import { Component } from 'vue';import PrimaryButton from './PrimaryButton.vue';import SecondaryButton from './SecondaryButton.vue';import DangerButton from './DangerButton.vue';
export type ButtonType = 'primary' | 'secondary' | 'danger';
export class ButtonFactory {static createButton(type: ButtonType): Component {switch (type) { case 'primary': return PrimaryButton; case 'secondary': return SecondaryButton; case 'danger': return DangerButton; default: return PrimaryButton;}}}<script setup lang="ts">import { computed } from 'vue';import { ButtonFactory, ButtonType } from './ButtonFactory';
const props = defineProps<{type: ButtonType;}>();
const ButtonComponent = computed(() => ButtonFactory.createButton(props.type));</script>
<template><component :is="ButtonComponent"><slot /></component></template>// Product Interfaceinterface Notification {send(message: string, recipient: string): void;}
// Concrete Productsclass EmailNotification implements Notification {send(message: string, recipient: string): void {console.log(`Sending email to ${recipient}: ${message}`);}}
class SMSNotification implements Notification {send(message: string, recipient: string): void {console.log(`Sending SMS to ${recipient}: ${message}`);}}
class PushNotification implements Notification {send(message: string, recipient: string): void {console.log(`Sending push notification to ${recipient}: ${message}`);}}
// Creatorabstract class NotificationService {abstract createNotification(): Notification;
notify(message: string, recipient: string): void {const notification = this.createNotification();notification.send(message, recipient);}}
// Concrete Creatorsclass EmailService extends NotificationService {createNotification(): Notification {return new EmailNotification();}}
class SMSService extends NotificationService {createNotification(): Notification {return new SMSNotification();}}
class PushService extends NotificationService {createNotification(): Notification {return new PushNotification();}}
// Usageconst emailService = new EmailService();emailService.notify("Welcome!", "user@example.com");
const smsService = new SMSService();smsService.notify("Your code is 1234", "+1234567890");Keep Products Simple
Ensure all products implement the same interface consistently.
Use Meaningful Names
Name your factories and products clearly to indicate their purpose.
Consider Simple Factory First
For simple cases, a single factory class might be sufficient.
Document Dependencies
Clearly document what each concrete creator produces.
| Factory Method | Simple Factory |
|---|---|
| Uses inheritance and subclasses | Uses a single factory class |
| More flexible and extensible | Simpler but less flexible |
| Follows Open / Closed Principle | Violates Open / Closed Principle |
| Better for complex hierarchies | Better for simple cases |
-When you don’t know beforehand the exact types of objects your code will work with
-When object creation is simple and straightforward