Monday, December 9, 2024

Adapter Pattern in C++

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:

  1. OldRectangle:

    • The existing class uses (x, y, width, height) for drawing.
  2. NewRectangle:

    • The new interface requires rectangles defined by (x1, y1, x2, y2).
  3. RectangleAdapter:

    • Adapts OldRectangle to conform to the NewRectangle interface.
    • Translates (x1, y1, x2, y2) into (x, y, width, height) for the OldRectangle.
  4. Client Code:

    • Uses the NewRectangle interface without any knowledge of the old API.
  5. 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

LeetCode C++ Cheat Sheet June

🎯 Core Patterns & Representative Questions 1. Arrays & Hashing Two Sum – hash map → O(n) Contains Duplicate , Product of A...