Introdução: por que precisamos de padrões de projeto em C++
Padrões de projeto (design patterns) são soluções comprovadas para problemas típicos que surgem no desenvolvimento de software. Em C++, com seu poderoso sistema de tipos, RAII e herança múltipla, os padrões adquirem flexibilidade especial. Eles ajudam a tornar o código mais legível, sustentável e escalável.
Neste artigo, veremos 4 padrões principais do catálogo GoF (Gang of Four): Singleton, Factory Method, Observer e Strategy. Cada padrão será ilustrado com um exemplo real de código em C++17/20.
Padrões de Criação: Singleton (Instância Única)
Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. Em C++, a abordagem moderna usa uma variável estática local (thread-safe a partir do C++11).
Exemplo: Logger de aplicação
class Logger {public: // Remove cópia e atribuição Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete;
static Logger& getInstance() { static Logger instance; // thread-safe desde C++11 return instance; }
void log(const std::string& message) { std::lock_guard<std::mutex> lock(m_mutex); std::cout << "[LOG] " << message << std::endl; }
private: Logger() = default; // construtor privado ~Logger() = default; std::mutex m_mutex;};
// Usoint main() { Logger::getInstance().log("Aplicação iniciada"); Logger::getInstance().log("Erro: arquivo não encontrado"); return 0;}Vantagens: garantia de singularidade, inicialização preguiçosa, segurança em threads.
Desvantagens: dificulta o teste (estado global), viola o princípio da responsabilidade única.
Padrões de Criação: Factory Method (Método Fábrica)
Factory Method define uma interface para criar um objeto, mas permite que subclasses decidam qual classe instanciar. Em C++, é frequentemente implementado por meio de funções virtuais e ponteiros inteligentes.
Exemplo: Geração de diferentes tipos de documentos
// Produto abstratoclass Document {public: virtual void open() = 0; virtual void save() = 0; virtual ~Document() = default;};
// Produtos concretosclass PDFDocument : public Document {public: void open() override { std::cout << "PDF aberto"; } void save() override { std::cout << "PDF salvo"; }};
class WordDocument : public Document {public: void open() override { std::cout << "Word aberto"; } void save() override { std::cout << "Word salvo"; }};
// Criador (Creator)class Application {public: virtual std::unique_ptr<Document> createDocument() = 0; virtual ~Application() = default;
void newDocument() { auto doc = createDocument(); doc->open(); // trabalho com o documento }};
// Criadores concretosclass PDFApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<PDFDocument>(); }};
class WordApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<WordDocument>(); }};
// Usoint main() { std::unique_ptr<Application> app = std::make_unique<PDFApplication>(); app->newDocument(); // Saída: "PDF aberto" return 0;}Este padrão é ideal quando os tipos exatos dos objetos a serem criados não são conhecidos antecipadamente.
Padrões Comportamentais: Observer (Observador)
Blogs
Book Recommendations
Leia também
Registro em aplicações TypeScript: melhores práticas
== e === em Swift: qual a diferença e o que está por baixo dos panos
Tratamento de Erros em TypeScript: try/catch, Classes Personalizadas e Tipagem Estrita
DateTime em ISO 8601 em C#: guia completo com respostas para perguntas frequentes
Microsserviços em JavaScript: arquitetura e prática do A ao Z