//
import CodeBlock from '@/components/mdx/CodeBlock'
import Tip from '@/components/mdx/Tip'
import Terminal from '@/components/mdx/Terminal'
import OutputBlock from '@/components/mdx/OutputBlock'
export const meta = { title: 'Practical Exercises for Creational Patterns', description: 'Hands-on exercises to apply creational patterns in real-world scenarios.', lastUpdated: '2026-05-15', readTime: '10 min read', order: 31 }
# Practical Exercises for Creational Patterns
## Introduction
Welcome to the second section of our design patterns curriculum, where we dive into **Creational Patterns**. These patterns are fundamental in object-oriented programming and help manage the instantiation process of objects. By understanding and applying these patterns, you can create more flexible, maintainable, and scalable software.
In this tutorial, we'll explore several creational patterns through practical exercises. We'll cover:
1. **Singleton Pattern**: Ensures a class has only one instance and provides a global point of access to it.
2. **Factory Method Pattern**: Defines an interface for creating an object, but lets subclasses decide which class to instantiate.
3. **Abstract Factory Pattern**: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
## Concept
### Singleton Pattern
The Singleton pattern is used when exactly one object is needed to coordinate actions across the system. This pattern ensures that a class has only one instance and provides a global point of access to it.
**Key Characteristics:**
- A private static variable holds the single instance.
- A public static method returns the instance, creating it if it doesn't exist.
### Factory Method Pattern
The Factory Method pattern defines an interface for creating an object in a superclass but allows subclasses to alter the type of objects that will be created. This pattern is useful when there are multiple classes that need to be instantiated and they share a common interface.
**Key Characteristics:**
- A factory method declares the creation operation.
- Subclasses implement the factory method to create specific types of products.
### Abstract Factory Pattern
The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. This pattern is useful when you need to manage a set of related products that must be used together.
**Key Characteristics:**
- An abstract factory declares the creation operations for each product type.
- Concrete factories implement these operations to create specific types of products.
## Examples
### Exercise 1: Singleton Pattern
Let's implement the Singleton pattern in JavaScript. We'll create a `DatabaseConnection` class that ensures only one instance is created and provides a global point of access to it.
<CodeBlock language="javascript">
{`class DatabaseConnection {
constructor() {
if (DatabaseConnection.instance) {
return DatabaseConnection.instance;
}
this.connection = 'Connected to the database';
DatabaseConnection.instance = this;
}
getConnection() {
return this.connection;
}
}
// Usage
const db1 = new DatabaseConnection();
const db2 = new DatabaseConnection();
console.log(db1 === db2); // true
console.log(db1.getConnection()); // Connected to the database`}
</CodeBlock>
<Tip variant="info">
Ensure that the Singleton pattern is used judiciously, as it can lead to tight coupling and make testing more difficult.
</Tip>
### Exercise 2: Factory Method Pattern
Now, let's implement the Factory Method pattern. We'll create a `Vehicle` interface and concrete classes for `Car` and `Bike`. A factory class will be responsible for creating these objects.
<CodeBlock language="javascript">
{`class Vehicle {
drive() {
throw new Error('This method must be overridden by subclasses.');
}
}
class Car extends Vehicle {
drive() {
return 'Driving a car';
}
}
class Bike extends Vehicle {
drive() {
return 'Riding a bike';
}
}
class VehicleFactory {
createVehicle(type) {
if (type === 'car') {
return new Car();
} else if (type === 'bike') {
return new Bike();
}
throw new Error('Unknown vehicle type');
}
}
// Usage
const factory = new VehicleFactory();
const car = factory.createVehicle('car');
console.log(car.drive()); // Driving a car
const bike = factory.createVehicle('bike');
console.log(bike.drive()); // Riding a bike`}
</CodeBlock>
<Tip variant="info">
The Factory Method pattern is particularly useful when you have a system that needs to be extended with new types of objects without modifying existing code.
</Tip>
### Exercise 3: Abstract Factory Pattern
Finally, let's implement the Abstract Factory pattern. We'll create an abstract factory for creating different types of UI components (e.g., `Button` and `Checkbox`). Concrete factories will implement these operations to create specific types of components.
<CodeBlock language="javascript">
{`class Button {
render() {
throw new Error('This method must be overridden by subclasses.');
}
}
class Checkbox {
render() {
throw new Error('This method must be overridden by subclasses.');
}
}
class WindowsButton extends Button {
render() {
return 'Rendering a Windows button';
}
}
class WindowsCheckbox extends Checkbox {
render() {
return 'Rendering a Windows checkbox';
}
}
class MacButton extends Button {
render() {
return 'Rendering a Mac button';
}
}
class MacCheckbox extends Checkbox {
render() {
return 'Rendering a Mac checkbox';
}
}
class GUIFactory {
createButton() {
throw new Error('This method must be overridden by subclasses.');
}
createCheckbox() {
throw new Error('This method must be overridden by subclasses.');
}
}
class WindowsGUIFactory extends GUIFactory {
createButton() {
return new WindowsButton();
}
createCheckbox() {
return new WindowsCheckbox();
}
}
class MacGUIFactory extends GUIFactory {
createButton() {
return new MacButton();
}
createCheckbox() {
return new MacCheckbox();
}
}
// Usage
const windowsFactory = new WindowsGUIFactory();
const windowsButton = windowsFactory.createButton();
console.log(windowsButton.render()); // Rendering a Windows button
const macFactory = new MacGUIFactory();
const macCheckbox = macFactory.createCheckbox();
console.log(macCheckbox.render()); // Rendering a Mac checkbox`}
</CodeBlock>
<Tip variant="info">
The Abstract Factory pattern is ideal for systems that need to be independent of how their products are created, composed, and represented.
</Tip>
## What's Next?
In the next section, we'll explore **Structural Patterns**. These patterns focus on how classes and objects can be composed to form larger structures. Structural patterns help in building flexible and reusable code.
Stay tuned for more practical exercises and insights into design patterns!