Padrões de Projeto em C++ com Exemplos: de A a Z
Padrões de projeto (design patterns) são soluções comprovadas para problemas típicos que surgem no desenvolvimento de software. Para C++, esses padrões são especialmente importantes, pois a linguagem combina programação orientada a objetos, genérica e de baixo nível. Neste artigo, abordaremos os principais padrões de projeto em C++ com exemplos de código que ajudarão você a escrever código mais flexível, reutilizável e de fácil manutenção.
Vamos considerar as três principais categorias de padrões de acordo com a classificação GoF (Gang of Four): criacionais, estruturais e comportamentais. Cada padrão será ilustrado com um exemplo real em C++.
1. Padrões Criacionais (Creational Patterns)
Os padrões criacionais abstraem o processo de criação de objetos, tornando o sistema independente de como os objetos são criados, compostos e representados.
1.1. Singleton (Instância Única)
O Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. Em C++, é frequentemente implementado por meio de um objeto local estático (thread-safe a partir do C++11).
class Logger {public: static Logger& getInstance() { static Logger instance; // inicialização thread-safe return instance; }
void log(const std::string& message) { std::cout << "[LOG] " << message << std::endl; }
private: Logger() = default; Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete;};
// Usoint main() { Logger::getInstance().log("Aplicação iniciada"); return 0;}Quando usar: gerenciamento de configuração, pools de threads, sistemas de logging.
1.2. Factory Method (Método Fábrica)
O Factory Method define uma interface para criar um objeto, mas permite que as subclasses decidam qual classe instanciar.
class Product {public: virtual void use() = 0; virtual ~Product() = default;};
class ConcreteProductA : public Product {public: void use() override { std::cout << "Produto A" << std::endl; }};
class ConcreteProductB : public Product {public: void use() override { std::cout << "Produto B" << std::endl; }};
class Creator {public: virtual Product* createProduct() = 0; void someOperation() { Product* p = createProduct(); p->use(); delete p; } virtual ~Creator() = default;};
class CreatorA : public Creator {public: Product* createProduct() override { return new ConcreteProductA(); }};
class CreatorB : public Creator {public: Product* createProduct() override { return new ConcreteProductB(); }};Quando usar: quando uma classe não sabe quais objetos de subclasses precisa criar.
2. Padrões Estruturais (Structural Patterns)
Os padrões estruturais descrevem como classes e objetos podem ser combinados em estruturas maiores, mantendo flexibilidade e eficiência.
2.1. Adapter (Adaptador)
O Adapter permite que objetos com interfaces incompatíveis trabalhem juntos. Em C++, é frequentemente implementado por meio de herança ou composição.
// Interface alvoclass Target {public: virtual void request() const { std::cout << "Requisição normal" << std::endl; } virtual ~Target() = default;};
// Classe adaptávelclass Adaptee {public: void specificRequest() const { std::cout << "Requisição específica" << std::endl; }};
// Adaptador (via composição)class Adapter : public Target {private: Adaptee* adaptee_;public: Adapter(Adaptee* a) : adaptee_(a) {} void request() const override { adaptee_->specificRequest(); }};