The Adapter Pattern is a structural design pattern used to enable two incompatible interfaces to work together. In JavaScript, the Adapter Pattern is typically used when you need to integrate a class or library with an existing system but the interfaces do not match. The Adapter pattern helps by creating a "wrapper" around the existing interface so that it can be used seamlessly with the new system or interface.
Key Concepts:
- Adaptee:
The existing interface or class that needs to be adapted to work with a
different interface.
- Adapter:
The class that implements the Adapter pattern. It wraps the Adaptee and
provides the expected interface.
- Target:
The expected interface or class that the system is designed to work with.
Example of Adapter Pattern in JavaScript
Imagine you have a legacy system that works with a OldPaymentSystem
interface, but you want to integrate a new NewPaymentSystem without changing
the existing code.
Without Adapter (Incompatible Systems):
// Old system's payment interface
class OldPaymentSystem {
processOldPayment(amount)
{
console.log(`Processing
payment of ${amount} using old system`);
}
}
// New system's payment interface
class NewPaymentSystem {
processPayment(amount)
{
console.log(`Processing
payment of ${amount} using new system`);
}
}
// Legacy system expecting old system's interface
class LegacyPaymentProcessor {
constructor(paymentSystem)
{
this.paymentSystem
= paymentSystem;
}
process(amount) {
this.paymentSystem.processOldPayment(amount);
}
}
// Incompatible new payment system with legacy system
const oldPaymentSystem = new OldPaymentSystem();
const legacyProcessor = new LegacyPaymentProcessor(oldPaymentSystem);
legacyProcessor.process(100); // Works fine
const newPaymentSystem = new NewPaymentSystem();
// legacyProcessor.process(newPaymentSystem); // This would
fail
In the above example, the new system (NewPaymentSystem)
can't directly be used by LegacyPaymentProcessor, because it expects the processOldPayment
method. This is where the Adapter pattern can help.
With Adapter (Using Adapter Pattern):
// Adaptee (Existing Interface)
class OldPaymentSystem {
processOldPayment(amount)
{
console.log(`Processing
payment of ${amount} using old system`);
}
}
// Target (New Interface)
class NewPaymentSystem {
processPayment(amount)
{
console.log(`Processing
payment of ${amount} using new system`);
}
}
// Adapter (Makes the Adaptee conform to the Target
interface)
class PaymentAdapter {
constructor(oldPaymentSystem)
{
this.oldPaymentSystem
= oldPaymentSystem;
}
processPayment(amount)
{
this.oldPaymentSystem.processOldPayment(amount);
// Adapting old interface to new one
}
}
// Now the new system can be used seamlessly with the legacy
code
class LegacyPaymentProcessor {
constructor(paymentSystem)
{
this.paymentSystem
= paymentSystem;
}
process(amount) {
this.paymentSystem.processPayment(amount);
}
}
// Usage:
const oldPaymentSystem = new OldPaymentSystem();
const adapter = new PaymentAdapter(oldPaymentSystem);
const legacyProcessor = new LegacyPaymentProcessor(adapter);
// Using the adapter
legacyProcessor.process(100); // Works with old system
through adapter
const newPaymentSystem = new NewPaymentSystem();
const newAdapter = new PaymentAdapter(newPaymentSystem);
const newLegacyProcessor = new LegacyPaymentProcessor(newAdapter);
// Using the adapter
newLegacyProcessor.process(200); // Works with new system
through adapter
Explanation:
- OldPaymentSystem:
The existing system with the processOldPayment method.
- NewPaymentSystem:
The new system with the processPayment method.
- PaymentAdapter:
The adapter that makes the old system compatible with the new interface.
- LegacyPaymentProcessor:
The class expecting the new interface (processPayment) but can work with
both the old and new systems due to the adapter.
In this case, the Adapter allows LegacyPaymentProcessor to work with both old and new systems without needing to modify its original design.
Advantages of Adapter Pattern:
- Code
Reusability: The Adapter allows reusing existing code (Adaptee)
without modifying it.
- Flexibility:
It lets you integrate systems with different interfaces.
- Decoupling:
It decouples the code from the specifics of the interfaces.
When to Use the Adapter Pattern:
- When
you want to integrate a new component into an existing system, but their
interfaces are incompatible.
- When
working with legacy code that you cannot modify but need to adapt for new
functionality.
No comments:
Post a Comment