Un Adaptador coge un tipo y genera una interfaz para algún otro tipo. Es útil cuando se tiene una librería o trozo de código que tiene una interfaz particular, y otra librería o trozo de código que usa las mismas ideas básicas que la primera librería, pero se expresa de forma diferente. Si se adaptan las formas de expresión entre sí, se puede crear una solución rápidamente.
Suponga que tiene una clase productora que genera los números de Fibonacci:
//: C10:FibonacciGenerator.h #ifndef FIBONACCIGENERATOR_H #define FIBONACCIGENERATOR_H class FibonacciGenerator { int n; int val[2]; public: FibonacciGenerator() : n(0) { val[0] = val[1] = 0; } int operator()() { int result = n > 2 ? val[0] + val[1] : n > 0 ? 1 : 0; ++n; val[0] = val[1]; val[1] = result; return result; } int count() { return n; } }; #endif // FIBONACCIGENERATOR_H ///:~
Listado 9.17. C10/FibonacciGenerator.h
Como es un productor, se usa llamando al operador(), de esta forma:
//: C10:FibonacciGeneratorTest.cpp #include <iostream> #include "FibonacciGenerator.h" using namespace std; int main() { FibonacciGenerator f; for(int i =0; i < 20; i++) cout << f.count() << ": " << f() << endl; } ///:~
Listado 9.18. C10/FibonacciGeneratorTest.cpp
A lo mejor le gustaría coger este generador y realizar operaciones de algoritmos numéricos STL con él. Desafortunadamente, los algoritmos STL sólo trabajan con iteradores, así que tiene dos interfaces que no casan. La solución es crear un adaptador que coja el FibonacciGenerator y produzca un iterador para los algoritmos STL a usar. Dado que los algoritmos numéricos sólo necesitan un iterador de entrada, el Adaptador es bastante directo (para algo que produce un iterador STL, es decir):
//: C10:FibonacciAdapter.cpp // Adapting an interface to something you already have. #include <iostream> #include <numeric> #include "FibonacciGenerator.h" #include "../C06/PrintSequence.h" using namespace std; class FibonacciAdapter { // Produce an iterator FibonacciGenerator f; int length; public: FibonacciAdapter(int size) : length(size) {} class iterator; friend class iterator; class iterator : public std::iterator< std::input_iterator_tag, FibonacciAdapter, ptrdiff_t> { FibonacciAdapter& ap; public: typedef int value_type; iterator(FibonacciAdapter& a) : ap(a) {} bool operator==(const iterator&) const { return ap.f.count() == ap.length; } bool operator!=(const iterator& x) const { return !(*this == x); } int operator*() const { return ap.f(); } iterator& operator++() { return *this; } iterator operator++(int) { return *this; } }; iterator begin() { return iterator(*this); } iterator end() { return iterator(*this); } }; int main() { const int SZ = 20; FibonacciAdapter a1(SZ); cout << "accumulate: " << accumulate(a1.begin(), a1.end(), 0) << endl; FibonacciAdapter a2(SZ), a3(SZ); cout << "inner product: " << inner_product(a2.begin(), a2.end(), a3.begin(), 0) << endl; FibonacciAdapter a4(SZ); int r1[SZ] = {0}; int* end = partial_sum(a4.begin(), a4.end(), r1); print(r1, end, "partial_sum", " "); FibonacciAdapter a5(SZ); int r2[SZ] = {0}; end = adjacent_difference(a5.begin(), a5.end(), r2); print(r2, end, "adjacent_difference", " "); } ///:~
Listado 9.19. C10/FibonacciAdapter.cpp
Se inicializa un FibonacciAdapter diciéndole cuán largo puede ser la secuencia de Fibonacci. Cuando se crea un iterador, simplemente captura una referencia al FibonacciAdapter que lo contiene para que pueda acceder al FibonacciGenerator y la longitud. Observe que la comparación de equivalencia ignora el valor de la derecha, porque el único asunto importante es si el generador ha alcanzado su longitud. Además, el operator++() no modifica el iterador; la única operación que cambia el estado del FibonacciAdapter es llamar a la función operator() del generador en el FibonacciGenerator. Puede aceptarse esta versión extremadamente simple del iterador porque las restricciones de un Input Iterator son muy estrictas; concretamente, sólo se puede leer cada valor de la secuencia una vez.
En main(), puede verse que los cuatro tipos distintos de algoritmos numéricos se testan satisfactoriamente con el FibonacciAdapter.