Introducción: ¿Por qué SOLID es importante para el desarrollador de C++?
\n\nSOLID es el acrónimo de cinco principios fundamentales de la programación orientada a objetos, formulados por Robert Martin (Tío Bob). Para el desarrollador de C++, estos principios no son solo teoría abstracta, sino una herramienta práctica que ayuda a crear aplicaciones flexibles, mantenibles y comprobables. En el mundo de C++, donde la gestión de memoria y el rendimiento son críticos, seguir SOLID permite evitar el "código espagueti" y simplifica la refactorización.
\n\nEn este artículo, analizaremos cada principio SOLID con ejemplos concretos en C++. Verá cómo la violación de los principios genera problemas y cómo solucionarlos. Usaremos C++ moderno (C++11/14/17/20) para que los ejemplos sean relevantes.
\n\n1. Single Responsibility Principle (SRP) — Principio de responsabilidad única
\n\nEsencia del principio
\nUna clase debe tener solo una razón para cambiar. En otras palabras, cada clase es responsable de una sola funcionalidad o aspecto del sistema.
\n\nViolación de SRP en C++
\nConsidere una clase que viola SRP: gestiona simultáneamente los datos de un informe y su formato.
\n\nclass Report {\npublic:\n void generateReport(const std::vector<Data>& data) {\n // Lógica de procesamiento de datos\n m_data = data;\n }\n \n void saveToFile(const std::string& filename) {\n // Lógica de guardado en archivo\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 salida a consola\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: si cambia el formato de salida, habrá que modificar la clase Report. Si cambia la forma de almacenar los datos, también. Esto viola SRP.
\n\nCorrección: separamos responsabilidades
\n\n// Solo responsable de los datos del informe\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// Solo responsable de guardar\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// Solo responsable de la salida a consola\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\nAhora cada clase tiene una sola razón para cambiar, lo que hace que el código sea más flexible y fácil de probar.
\n\n2. Open-Closed Principle (OCP) — Principio de abierto/cerrado
\n\nEsencia del principio
\nLas entidades de software (clases, módulos, funciones) deben estar abiertas para extensión, pero cerradas para modificación. Esto significa que debe poder agregar nueva funcionalidad sin modificar el código existente.
\n\nViolación de OCP en C++
\nImagine un sistema de cálculo de descuentos donde se usa if-else para cada tipo de cliente.
\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