Abstract Factory Pattern
Introduction
The Abstract Factory pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. This pattern is especially useful for systems that need to be independent of how their objects are created, composed, and represented.
Purpose
- To provide an interface for creating families of related or dependent objects without specifying their concrete classes.
- To encapsulate a group of individual factories with a common goal.
Use Cases
- When the system needs to be independent of how its products are created, composed, and represented.
- When families of related products are designed to be used together, and you need to enforce this constraint.
Advantages/Disadvantages
Advantages:
- Isolates concrete classes: The client code is separated from the implementation details of derived products.
- Makes exchanging product families easy: The class of a concrete factory appears only once in an application.
Disadvantages:
- Can be more complex to implement due to the multiple layers of abstraction.
- Adding new kinds of products can be challenging as it might require extending the interface, affecting all concrete factories.
Implementation in JavaScript
class AbstractFactory {
createProductA() {}
createProductB() {}
}
class ConcreteFactory1 extends AbstractFactory {
createProductA() {
return new ProductA1();
}
createProductB() {
return new ProductB1();
}
}
class ConcreteFactory2 extends AbstractFactory {
createProductA() {
return new ProductA2();
}
createProductB() {
return new ProductB2();
}
}
class ProductA1 {}
class ProductB1 {}
class ProductA2 {}
class ProductB2 {}
// Usage
const factory1 = new ConcreteFactory1();
const productA1 = factory1.createProductA();
const productB1 = factory1.createProductB();
const factory2 = new ConcreteFactory2();
const productA2 = factory2.createProductA();
const productB2 = factory2.createProductB();
Practical Example
class GUIFactory {
createButton() {}
createCheckbox() {}
}
class WinFactory extends GUIFactory {
createButton() {
return new WinButton();
}
createCheckbox() {
return new WinCheckbox();
}
}
class MacFactory extends GUIFactory {
createButton() {
return new MacButton();
}
createCheckbox() {
return new MacCheckbox();
}
}
class WinButton {
render() {
return 'Windows Button';
}
}
class WinCheckbox {
render() {
return 'Windows Checkbox';
}
}
class MacButton {
render() {
return 'Mac Button';
}
}
class MacCheckbox {
render() {
return 'Mac Checkbox';
}
}
// Usage
function createUI(factory) {
const button = factory.createButton();
const checkbox = factory.createCheckbox();
console.log(button.render());
console.log(checkbox.render());
}
createUI(new WinFactory()); // Windows Button, Windows Checkbox
createUI(new MacFactory()); // Mac Button, Mac Checkbox
In this practical example, GUIFactory
serves as an abstract factory for creating a family of GUI elements. WinFactory
and MacFactory
are concrete factories that produce Windows and Mac styled GUI elements, respectively. This pattern allows for the creation of consistent-looking GUIs across different operating systems.