O Adapter é um padrão de projeto estrutural, que permite a colaboração de objetos incompatíveis.
O Adapter atua como um wrapper entre dois objetos. Ele captura chamadas para um objeto e as deixa reconhecíveis tanto em formato como interface para este segundo objeto.
Exemplos de uso: O padrão Adapter é bastante comum no código C++. É frequentemente usado em sistemas baseados em algum código legado. Nesses casos, os adaptadores criam código legado com classes modernas.
Identificação: O adapter é reconhecível por um construtor que utiliza uma instância de tipo abstrato/interface diferente. Quando o adaptador recebe uma chamada para qualquer um de seus métodos, ele converte parâmetros para o formato apropriado e direciona a chamada para um ou vários métodos do objeto envolvido.
Exemplo conceitual
Este exemplo ilustra a estrutura do padrão de projeto Adapter. Ele se concentra em responder a estas perguntas:
De quais classes ele consiste?
Quais papéis essas classes desempenham?
De que maneira os elementos do padrão estão relacionados?
main.cc: Exemplo conceitual
/** * The Target defines the domain-specific interface used by the client code. */ class Target { public: virtual ~Target() = default; virtual std::string Request() const { return "Target: The default target's behavior."; } }; /** * The Adaptee contains some useful behavior, but its interface is incompatible * with the existing client code. The Adaptee needs some adaptation before the * client code can use it. */ class Adaptee { public: std::string SpecificRequest() const { return ".eetpadA eht fo roivaheb laicepS"; } }; /** * The Adapter makes the Adaptee's interface compatible with the Target's * interface. */ class Adapter : public Target { private: Adaptee *adaptee_; public: Adapter(Adaptee *adaptee) : adaptee_(adaptee) {} std::string Request() const override { std::string to_reverse = this->adaptee_->SpecificRequest(); std::reverse(to_reverse.begin(), to_reverse.end()); return "Adapter: (TRANSLATED) " + to_reverse; } }; /** * The client code supports all classes that follow the Target interface. */ void ClientCode(const Target *target) { std::cout << target->Request(); } int main() { std::cout << "Client: I can work just fine with the Target objects:\n"; Target *target = new Target; ClientCode(target); std::cout << "\n\n"; Adaptee *adaptee = new Adaptee; std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:\n"; std::cout << "Adaptee: " << adaptee->SpecificRequest(); std::cout << "\n\n"; std::cout << "Client: But I can work with it via the Adapter:\n"; Adapter *adapter = new Adapter(adaptee); ClientCode(adapter); std::cout << "\n"; delete target; delete adaptee; delete adapter; return 0; }
Output.txt: Resultados da execução
Client: I can work just fine with the Target objects: Target: The default target's behavior. Client: The Adaptee class has a weird interface. See, I don't understand it: Adaptee: .eetpadA eht fo roivaheb laicepS Client: But I can work with it via the Adapter: Adapter: (TRANSLATED) Special behavior of the Adaptee.
Herança múltipla
Em C ++, o padrão Adapter pode ser implementado usando herança múltipla.
main.cc: Herança múltipla
/** * The Target defines the domain-specific interface used by the client code. */ class Target { public: virtual ~Target() = default; virtual std::string Request() const { return "Target: The default target's behavior."; } }; /** * The Adaptee contains some useful behavior, but its interface is incompatible * with the existing client code. The Adaptee needs some adaptation before the * client code can use it. */ class Adaptee { public: std::string SpecificRequest() const { return ".eetpadA eht fo roivaheb laicepS"; } }; /** * The Adapter makes the Adaptee's interface compatible with the Target's * interface using multiple inheritance. */ class Adapter : public Target, public Adaptee { public: Adapter() {} std::string Request() const override { std::string to_reverse = SpecificRequest(); std::reverse(to_reverse.begin(), to_reverse.end()); return "Adapter: (TRANSLATED) " + to_reverse; } }; /** * The client code supports all classes that follow the Target interface. */ void ClientCode(const Target *target) { std::cout << target->Request(); } int main() { std::cout << "Client: I can work just fine with the Target objects:\n"; Target *target = new Target; ClientCode(target); std::cout << "\n\n"; Adaptee *adaptee = new Adaptee; std::cout << "Client: The Adaptee class has a weird interface. See, I don't understand it:\n"; std::cout << "Adaptee: " << adaptee->SpecificRequest(); std::cout << "\n\n"; std::cout << "Client: But I can work with it via the Adapter:\n"; Adapter *adapter = new Adapter; ClientCode(adapter); std::cout << "\n"; delete target; delete adaptee; delete adapter; return 0; }
Output.txt: Resultados da execução
Client: I can work just fine with the Target objects: Target: The default target's behavior. Client: The Adaptee class has a weird interface. See, I don't understand it: Adaptee: .eetpadA eht fo roivaheb laicepS Client: But I can work with it via the Adapter: Adapter: (TRANSLATED) Special behavior of the Adaptee.