006
GOF Structural

Adapter

The adapter aims to be a converter between two specific interfaces: one belonging to “our” side of the application, the other to the library or other tool we need to interact with. This is very important, because it enables us to delay decisions, as the choice of a spcific implementation of the adapter becomes less important due to the fact that we are at that point using the adapter itself as our communication contract.

Usage

Often used in combo with other patterns, such as [Inversion of Control] and several Factories

Examples

Typical example of this pattern in a “pure” form is the Driver. Whether it is for printing or for database access, the API exposed by the common development systems just require the connection to the adapter and, with some kind of Factory or repository we get the specific implementation of what we need at the moment, based on the configuration of the system we have.

Specimens

15 implementations
Specimen 006.01 Dart View specimen ↗

The Adapter pattern converts the interface of a class into another interface clients expect. It lets classes work together that couldn’t otherwise because of incompatible interfaces. In this Dart example, we have a LegacyPrinter with a printLegacy() method and a ModernPrinter interface expecting printModern(). The PrinterAdapter adapts the LegacyPrinter to fulfill the ModernPrinter interface, enabling a ModernPrintingService to work with it. This follows Dart’s use of interfaces (implemented by implements) and class composition to achieve adaptation.

// The target interface that clients can work with.
abstract class ModernPrinter {
  void printModern(String text);
}

// The legacy class with an incompatible interface.
class LegacyPrinter {
  void printLegacy(String text) {
    print('Legacy Printer: Printing - $text');
  }
}

// The adapter class that makes the legacy class compatible.
class PrinterAdapter implements ModernPrinter {
  final LegacyPrinter legacyPrinter;

  PrinterAdapter(this.legacyPrinter);

  @override
  void printModern(String text) {
    legacyPrinter.printLegacy(text);
  }
}

// Client code that uses the modern interface
class ModernPrintingService {
  void printDocument(ModernPrinter printer, String document) {
    print('Modern Printing Service: Preparing document...');
    printer.printModern(document);
    print('Modern Printing Service: Document printed.');
  }
}

void main() {
  final legacyPrinter = LegacyPrinter();
  final adapter = PrinterAdapter(legacyPrinter);
  final printingService = ModernPrintingService();

  printingService.printDocument(adapter, 'Hello, Adapted World!');
}