Introdução: Por que SOLID é importante para o desenvolvedor C++?
\n\nSOLID é um acrônimo de cinco princípios fundamentais da programação orientada a objetos, formulados por Robert Martin (Tio Bob). Para o desenvolvedor C++, esses princípios não são apenas teoria abstrata, mas uma ferramenta prática que ajuda a criar aplicações flexíveis, sustentáveis e testáveis. No mundo do C++, onde o gerenciamento de memória e o desempenho são críticos, seguir SOLID permite evitar "código espaguete" e simplifica a refatoração.
\n\nNeste artigo, analisaremos cada princípio SOLID com exemplos concretos em C++. Você verá como a violação dos princípios leva a problemas e como corrigi-los. Usaremos C++ moderno (C++11/14/17/20) para que os exemplos sejam atuais.
\n\n1. Single Responsibility Principle (SRP) — Princípio da Responsabilidade Única
\n\nEssência do princípio
\nUma classe deve ter apenas um motivo para mudar. Em outras palavras, cada classe é responsável por apenas uma funcionalidade ou aspecto do sistema.
\n\nViolação do SRP em C++
\nConsidere uma classe que viola o SRP: ela gerencia simultaneamente os dados de um relatório e sua formatação.
\n\nclass Report {\npublic:\n void generateReport(const std::vector<Data>& data) {\n // Lógica de processamento de dados\n m_data = data;\n }\n \n void saveToFile(const std::string& filename) {\n // Lógica de salvamento em arquivo\n std::ofstream file(filename);\n for (const auto& item : m_data) {\n file << item.toString() << "\\n";\n }\n }\n \n void printToConsole() {\n // Lógica de exibição no console\n for (const auto& item : m_data) {\n std::cout << item.toString() << std::endl;\n }\n }\n \nprivate:\n std::vector<Data> m_data;\n};\n\nProblema: se o formato de saída mudar, será necessário alterar a classe Report. Se a forma de armazenamento dos dados mudar, também. Isso viola o SRP.
\n\nCorrigindo: separando as responsabilidades
\n\n// Responsável apenas pelos dados do relatório\nclass ReportData {\npublic:\n void addData(const Data& item) {\n m_data.push_back(item);\n }\n \n const std::vector<Data>& getData() const {\n return m_data;\n }\n \nprivate:\n std::vector<Data> m_data;\n};\n\n// Responsável apenas pelo salvamento\nclass FileSaver {\npublic:\n void save(const std::string& filename, const ReportData& report) {\n std::ofstream file(filename);\n for (const auto& item : report.getData()) {\n file << item.toString() << "\\n";\n }\n }\n};\n\n// Responsável apenas pela exibição no console\nclass ConsolePrinter {\npublic:\n void print(const ReportData& report) {\n for (const auto& item : report.getData()) {\n std::cout << item.toString() << std::endl;\n }\n }\n};\n\nAgora cada classe tem um único motivo para mudar, tornando o código mais flexível e fácil de testar.
\n\n2. Open-Closed Principle (OCP) — Princípio do Aberto/Fechado
\n\nEssência do princípio
\nEntidades de software (classes, módulos, funções) devem estar abertas para extensão, mas fechadas para modificação. Isso significa que você deve ser capaz de adicionar nova funcionalidade sem alterar o código existente.
\n\nViolação do OCP em C++
\nImagine um sistema de cálculo de descontos onde, para cada tipo de cliente, é usado if-else.
\n\nclass DiscountCalculator {\npublic:\n double calculateDiscount(const std::string& customerType, double amount) {\n if (customerType == "regular") {\n return amount * 0.1; // 10%\n } else if (customerType == "vip") {\n return amount * 0.2; // 20%\n } else if (customerType == "premium") {\n return amount * 0.3; // 30%\n }\n