Introdução aos Padrões de Projeto em C++
Padrões de projeto (design patterns) são soluções arquiteturais testadas pelo tempo para problemas típicos de desenvolvimento. No mundo do C++, eles são especialmente importantes, pois permitem criar código flexível, extensível e de fácil manutenção. Neste artigo, vamos analisar quatro padrões fundamentais: Singleton, Factory Method, Observer e Strategy — com exemplos completos em C++ moderno (C++17/20).
Cada padrão será acompanhado por um exemplo prático, diagrama de classes e explicações sobre sua aplicação. O material é voltado para desenvolvedores que já conhecem os fundamentos de C++ e POO.
1. Padrão Criacional Singleton
Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. Em C++, a implementação clássica usa um método estático e um construtor privado.
Quando usar
- Gerenciamento de conexão com banco de dados
- Sistema de logging
- Gerenciador de cache
- Configuração da aplicação
Exemplo de implementação (Singleton thread-safe)
#include <iostream>#include <mutex>#include <memory>
class Logger {private: static std::unique_ptr<Logger> instance; static std::mutex mtx; Logger() { std::cout << "Logger criado" << std::endl; } public: Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; static Logger* getInstance() { std::lock_guard<std::mutex> lock(mtx); if (!instance) { instance.reset(new Logger()); } return instance.get(); } void log(const std::string& msg) { std::cout << "[LOG] " << msg << std::endl; }};
std::unique_ptr<Logger> Logger::instance = nullptr;std::mutex Logger::mtx;
int main() { Logger* log1 = Logger::getInstance(); Logger* log2 = Logger::getInstance(); log1->log("Mensagem de teste"); // log1 e log2 apontam para o mesmo objeto std::cout << "log1 == log2: " << (log1 == log2) << std::endl; return 0;}Abordagem C++ moderna (Meyers' Singleton)
class ConfigManager {public: static ConfigManager& getInstance() { static ConfigManager instance; // thread-safe a partir do C++11+ return instance; } void setParam(const std::string& key, const std::string& value) { params[key] = value; } std::string getParam(const std::string& key) { return params[key]; } private: ConfigManager() = default; std::map<std::string, std::string> params;};2. Padrão Criacional Factory Method
Factory Method define uma interface para criar um objeto, mas permite que subclasses escolham a classe concreta do objeto a ser criado. Esse padrão é especialmente útil quando o tipo do objeto não é conhecido antecipadamente.
Estrutura do padrão
- Product — classe abstrata do produto
- ConcreteProduct — implementação concreta do produto
- Creator — classe abstrata do criador com o método fábrica
- ConcreteCreator — sobrescreve o método fábrica
Exemplo: sistema de notificações
#include <iostream>#include <memory>#include <string>
// Produto abstratoclass Notification {public: virtual void send(const std::string& message) = 0; virtual ~Notification() = default;};
// Produtos concretosclass EmailNotification : public Notification {public: void send(const std::str