Princípios SOLID em C++: da teoria à prática
SOLID é um acrônimo de cinco princípios fundamentais da programação orientada a objetos, formulados por Robert Martin (Uncle Bob). No contexto de C++, esses princípios ajudam a criar código flexível, sustentável e testável. Neste artigo, vamos analisar cada princípio com exemplos práticos em C++.
1. Single Responsibility Principle (SRP) — Princípio da Responsabilidade Única
Essência: Cada classe deve ter apenas uma razão para mudar. Em palavras simples — a classe lida com apenas uma tarefa.
Exemplo ruim (violação do SRP):
class Report {public: void generateReport() { /* geração do relatório */ } void saveToFile(const std::string& filename) { /* salvar em arquivo */ } void printReport() { /* imprimir relatório */ }};Aqui, a classe Report é responsável por gerar, salvar e imprimir — três responsabilidades diferentes.
Exemplo bom (respeitando o SRP):
class Report {public: std::string generate() { /* geração do relatório */ return "dados do relatório"; }};
class ReportSaver {public: void save(const std::string& data, const std::string& filename) { // salvar em arquivo }};
class ReportPrinter {public: void print(const std::string& data) { // imprimir relatório }};Agora cada classe tem uma responsabilidade clara, o que simplifica os testes e a modificação.
2. Open-Closed Principle (OCP) — Princípio Aberto/Fechado
Essência: As classes devem estar abertas para extensão, mas fechadas para modificação. Você deve ser capaz de adicionar novas funcionalidades sem alterar o código existente.
Exemplo ruim:
enum class ShapeType { Circle, Rectangle };
class Shape {public: ShapeType type;};
class AreaCalculator {public: double calculateArea(const Shape& shape) { if (shape.type == ShapeType::Circle) { // cálculo da área do círculo return 3.14 * radius * radius; } else if (shape.type == ShapeType::Rectangle) { // cálculo da área do retângulo return width * height; } return 0.0; }};Ao adicionar uma nova forma (por exemplo, triângulo), será necessário modificar AreaCalculator.
Exemplo bom (através de polimorfismo):
class Shape {public: virtual double area() const = 0; virtual ~Shape() = default;};
class Circle : public Shape { double radius;public: explicit Circle(double r) : radius(r) {} double area() const override { return 3.14159 * radius * radius; }};
class Rectangle : public Shape { double width, height;public: Rectangle(double w, double h) : width(w), height(h) {} double area() const override { return width * height; }};
class AreaCalculator {public: double calculateArea(const Shape& shape) { return shape.area(); }};Agora, para adicionar uma nova forma, basta criar uma nova classe derivada, sem tocar em AreaCalculator.
3. Liskov Substitution Principle (LSP) — Princípio da Substituição de Barbara Liskov
Essência: Objetos de subclasses devem ser intercambiáveis com objetos da classe base sem quebrar a correção do programa.
Violacão clássica (retângulo-quadrado):
class Rectangle {protected: int width, height;public: void setWidth(int w) { width = w; } void setHeight(int h) { height = h; } int area() const { return width * height; }};
class Square : public Rectangle {public: void setWidth(int w) override { width = w; height
```