Ответ
Я использовал паттерн Адаптер (Adapter) для интеграции сторонних библиотек или унаследованного кода, интерфейс которого не совместим с интерфейсом, ожидаемым в моей системе. Он позволяет работать со старым кодом, не изменяя его.
Типичный пример из моего опыта: нужно было использовать старую библиотеку для работы с графикой (например, с устаревшим API рисования), в то время как основное приложение работало с современным интерфейсом ModernRenderer.
// Интерфейс, который ожидает наша система (Цель)
class ModernRenderer {
public:
virtual void drawShape(float x, float y, float width, float height) = 0;
};
// Устаревший класс, который нужно адаптировать (Адаптируемый)
class LegacyGraphics {
public:
void render(int x1, int y1, int x2, int y2) {
// Старый код рисования прямоугольника
std::cout << "Legacy draw: (" << x1 << "," << y1 << ") to (" << x2 << "," << y2 << ")n";
}
};
// Адаптер, наследует цель и содержит адаптируемый объект
class GraphicsAdapter : public ModernRenderer {
LegacyGraphics* legacyGraphics;
public:
GraphicsAdapter(LegacyGraphics* lg) : legacyGraphics(lg) {}
void drawShape(float x, float y, float w, float h) override {
// Преобразуем новый интерфейс в старый
legacyGraphics->render(static_cast<int>(x), static_cast<int>(y),
static_cast<int>(x + w), static_cast<int>(y + h));
}
};
// Использование в клиентском коде
int main() {
LegacyGraphics oldLib;
GraphicsAdapter adapter(&oldLib);
// Теперь можно использовать старую библиотеку через новый интерфейс
ModernRenderer* renderer = &adapter;
renderer->drawShape(10.5f, 20.5f, 100.0f, 50.0f);
return 0;
}
Я применяю Adapter, когда нужно повторно использовать проверенный, но устаревший код, и когда изменение его исходников невозможно или нецелесообразно.