Adapter Pattern
The Adapter Pattern allows incompatible interfaces to work together by converting the interface of one class into another that the client expects.
example of the Adapter Pattern in C++, demonstrating its use in adapting incompatible APIs:
Scenario:
You have an OldRectangle class that draws rectangles using a top-left corner and dimensions (x, y, width, height). However, your new drawing system expects rectangles to be defined by their diagonal corners (x1, y1, x2, y2).
The Adapter will allow the old class to work with the new interface.
Implementation:
#include <iostream>
// OldRectangle class (legacy API)
class OldRectangle {
public:
void draw(int x, int y, int width, int height) {
std::cout << "Drawing rectangle with top-left (" << x << ", " << y
<< ") and dimensions " << width << "x" << height << ".\n";
}
};
// Target interface (new API)
class NewRectangle {
public:
virtual void draw(int x1, int y1, int x2, int y2) = 0;
virtual ~NewRectangle() = default;
};
// Adapter class to adapt OldRectangle to NewRectangle
class RectangleAdapter : public NewRectangle {
private:
OldRectangle* oldRectangle;
public:
RectangleAdapter(OldRectangle* rectangle) : oldRectangle(rectangle) {}
void draw(int x1, int y1, int x2, int y2) override {
int x = x1; // Top-left x
int y = y1; // Top-left y
int width = x2 - x1; // Calculate width
int height = y2 - y1; // Calculate height
oldRectangle->draw(x, y, width, height); // Call old API
}
};
// Client code
void clientCode(NewRectangle& rectangle) {
rectangle.draw(2, 3, 7, 8); // New API expects (x1, y1, x2, y2)
}
int main() {
OldRectangle oldRectangle;
RectangleAdapter adapter(&oldRectangle);
clientCode(adapter); // Use adapter to draw using the old API
return 0;
}
Explanation:
-
OldRectangle:
- The existing class uses
(x, y, width, height)for drawing.
- The existing class uses
-
NewRectangle:
- The new interface requires rectangles defined by
(x1, y1, x2, y2).
- The new interface requires rectangles defined by
-
RectangleAdapter:
- Adapts
OldRectangleto conform to theNewRectangleinterface. - Translates
(x1, y1, x2, y2)into(x, y, width, height)for theOldRectangle.
- Adapts
-
Client Code:
- Uses the
NewRectangleinterface without any knowledge of the old API.
- Uses the
-
Output:
Drawing rectangle with top-left (2, 3) and dimensions 5x5.
Key Points:
- The Adapter handles the mismatch between old and new APIs seamlessly.
- The client code works with the new interface and does not need modification.
- This design ensures backward compatibility and promotes reusability.
Example: Adapting an Old System to a New Interface
#include <iostream>
#include <string>
// Old interface (incompatible with the client's code)
class OldPrinter {
public:
void print(const std::string& message) {
std::cout << "Old Printer: " << message << "\n";
}
};
// Target interface (the new standard the client expects)
class INewPrinter {
public:
virtual void printMessage(const std::string& message) = 0;
virtual ~INewPrinter() = default;
};
// Adapter to make OldPrinter compatible with INewPrinter
class PrinterAdapter : public INewPrinter {
private:
OldPrinter& oldPrinter;
public:
PrinterAdapter(OldPrinter& printer) : oldPrinter(printer) {}
void printMessage(const std::string& message) override {
oldPrinter.print(message); // Delegate call to OldPrinter
}
};
// Client code
void clientCode(INewPrinter& printer) {
printer.printMessage("Hello, World!");
}
int main() {
OldPrinter oldPrinter;
PrinterAdapter adapter(oldPrinter);
clientCode(adapter);
return 0;
}
Output:
Old Printer: Hello, World!
Key Points
Observer Pattern:
- Use when multiple objects (observers) need to react to changes in another object (subject).
Adapter Pattern:
- Use when you need to make an existing class compatible with a new interface without modifying the existing class.
These examples showcase the basic structure of each pattern for easy understanding and implementation.
No comments:
Post a Comment