Design patterns are established solutions to frequent challenges in software design. By utilizing them, developers can enhance code readability, scalability, and maintainability. This article explores how TypeScript, an increasingly popular superset of JavaScript improves these patterns with its type safety and modern features. Whether you’re developing a large-scale application or a side project, grasping design patterns in TypeScript will boost your development skills.
Design patterns are reusable, generic solutions to common challenges in software design. They aren't actual code but rather templates for addressing these issues. Originating from the "Gang of Four" (GoF) book, these patterns fall into three main categories:
TypeScript’s features make implementing design patterns more robust:
1. Static Typing: Errors are caught at compile time, reducing runtime bugs.
2. Interfaces and Generics: Allow more precise and flexible implementations.
3. Enum and Union Types: Simplify certain patterns, such as state management.
4. Enhanced Tooling: With IDE support, TypeScript boosts productivity.
Ensures that a class has only one instance and provides a global point of access to it.
Implementation in TypeScript:
class Singleton { private static instance: Singleton; private constructor() {} // Prevent instantiation public static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } } const instance1 = Singleton.getInstance(); const instance2 = Singleton.getInstance(); console.log(instance1 === instance2); // true
Use Case: Managing configuration settings or database connections.
Provides an interface for creating objects without specifying their exact classes.
Implementation:
interface Button { render(): void; } class WindowsButton implements Button { render() { console.log("Rendering Windows button"); } } class MacButton implements Button { render() { console.log("Rendering Mac button"); } } class ButtonFactory { static createButton(os: string): Button { if (os === "Windows") return new WindowsButton(); if (os === "Mac") return new MacButton(); throw new Error("Unknown OS"); } } const button = ButtonFactory.createButton("Mac"); button.render(); // Output: Rendering Mac button
Use Case: UI frameworks for cross-platform applications.
Defines a one-to-many relationship, where changes in one object are notified to all its dependents.
Implementation:
class Subject { private observers: Array<() => void> = []; addObserver(observer: () => void) { this.observers.push(observer); } notifyObservers() { this.observers.forEach(observer => observer()); } } const subject = new Subject(); subject.addObserver(() => console.log("Observer 1 notified!")); subject.addObserver(() => console.log("Observer 2 notified!")); subject.notifyObservers();
Use Case: Reactivity in front-end frameworks like Angular or React.
Defines a family of algorithms, encapsulates each, and makes them interchangeable.
Implementation:
interface PaymentStrategy { pay(amount: number): void; } class CreditCardPayment implements PaymentStrategy { pay(amount: number) { console.log(`Paid ${amount} using Credit Card`); } } class PayPalPayment implements PaymentStrategy { pay(amount: number) { console.log(`Paid ${amount} using PayPal`); } } class PaymentContext { constructor(private strategy: PaymentStrategy) {} executePayment(amount: number) { this.strategy.pay(amount); } } const payment = new PaymentContext(new PayPalPayment()); payment.executePayment(100); // Paid 100 using PayPal
Use Case: Payment systems in e-commerce platforms.
Adds new functionality to an object dynamically.
Implementation:
class Singleton { private static instance: Singleton; private constructor() {} // Prevent instantiation public static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } } const instance1 = Singleton.getInstance(); const instance2 = Singleton.getInstance(); console.log(instance1 === instance2); // true
Use Case: Adding features to a product in a shopping cart.
|
Category |
Use Case |
Benefit |
||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Singleton | Creational | Managing global state like configurations | Guarantees single instance | ||||||||||||||||||||||||
Factory | Creational | UI components or APIs | Decouples creation logic | ||||||||||||||||||||||||
Observer | Behavioral | Event systems in frameworks | Simplifies communication | ||||||||||||||||||||||||
Strategy | Behavioral | Algorithm selection in runtime | Enhances flexibility | ||||||||||||||||||||||||
Decorator | Structural | Extending class functionality | Adds dynamic capabilities |
Refactoring to Patterns
Joshua Kerievsky
See you in the next article, lad! ?
My personal website: https://shafayet.zya.me
The above is the detailed content of Harnessing Functional Programming with JavaScript. For more information, please follow other related articles on the PHP Chinese website!