Behavioral design patterns are a category of software design patterns that focus on the interaction between objects. They define the ways in which objects communicate and collaborate with each other, making it easier to manage complex systems by encapsulating common communication patterns into reusable solutions. Understanding behavioral patterns can help developers create more flexible, maintainable, and scalable code.
Behavioral patterns are concerned with how objects interact and communicate. They provide templates for managing the interactions between different parts of a system. These patterns are particularly useful in scenarios where you need to define complex communication protocols or when you want to decouple the sender from the receiver.
Some common behavioral design patterns include:
The Strategy pattern allows you to define a family of algorithms, encapsulate each one, and make them interchangeable. This pattern lets the algorithm vary independently from clients that use it.
<CodeBlock language="javascript">
{`// Define the strategy interface
class PaymentStrategy {
pay(amount) {}
}
// Concrete strategies
class CreditCardPayment extends PaymentStrategy {
constructor(name, cardNumber, cvv, expiryDate) {
this.name = name;
this.cardNumber = cardNumber;
this.cvv = cvv;
this.expiryDate = expiryDate;
}
pay(amount) {
console.log(\`\${amount} paid with credit/debit card\`);
}
}
class PayPalPayment extends PaymentStrategy {
constructor(email, password) {
this.email = email;
this.password = password;
}
pay(amount) {
console.log(\`\${amount} paid using PayPal.\`);
}
}
// Context
class ShoppingCart {
constructor() {
this.paymentStrategy = null;
}
setPaymentStrategy(strategy) {
this.paymentStrategy = strategy;
}
checkout(amount) {
if (this.paymentStrategy) {
this.paymentStrategy.pay(amount);
} else {
console.log('No payment strategy selected.');
}
}
}
// Usage
const cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment('John Doe', '1234567890123456', '123', '12/25'));
cart.checkout(100);
cart.setPaymentStrategy(new PayPalPayment('john.doe@example.com', 'password123'));
cart.checkout(200);`}
</CodeBlock>
### Observer Pattern Example
The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
```jsx
<CodeBlock language="javascript">
{`// Subject class
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notifyObservers(message) {
this.observers.forEach(observer => observer.update(message));
}
}
// Observer class
class Observer {
constructor(name) {
this.name = name;
}
update(message) {
console.log(\`\${this.name} received message: \${message}\`);
}
}
// Usage
const subject = new Subject();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers('Hello Observers!'); // Output: Observer 1 received message: Hello Observers! Observer 2 received message: Hello Observers!
subject.removeObserver(observer1);
subject.notifyObservers('Observer 1 has been removed.'); // Output: Observer 2 received message: Observer 1 has been removed.`}
</CodeBlock>
## What's Next?
In the next section, we will dive deeper into the **Chain of Responsibility Pattern**. This pattern is particularly useful for scenarios where you want to pass a request along a chain of potential handlers until one of them handles the request.
Stay tuned!