Skip to content

Picoquio/DevelopmentChallenge

Repository files navigation

DevelopmentChallenge — Refactor de FormaGeometrica

Refactor de un módulo de reporte de formas geométricas, aplicando principios de programación orientada a objetos para facilitar la extensión de nuevas formas e idiomas sin modificar código existente.


Problema original

La clase FormaGeometrica concentraba toda la responsabilidad en un único archivo: calculaba áreas y perímetros, generaba el reporte, y manejaba las traducciones mediante switch e if anidados con constantes enteras (int tipo, int idioma). Agregar una nueva forma o un nuevo idioma requería modificar múltiples métodos en la misma clase.


Solución

Se descompuso la clase original en una jerarquía de interfaces e implementaciones independientes.

Estructura de carpetas

DevelopmentChallenge.Data/
├── Interfaces/
│   ├── IFormaGeometrica.cs      # Contrato para toda forma geométrica
│   └── IIdioma.cs               # Contrato para todo idioma
├── Formas/
│   └── Formas.cs                # Cuadrado, Circulo, TrianguloEquilatero, Trapecio, Rectangulo
├── Idiomas/
│   ├── Castellano.cs
│   ├── Ingles.cs
└── Classes/
    └── ReporteFormas.cs         # Orquestador del reporte

DevelopmentChallenge.Data.Tests/
├── DataTests.cs                 # Tests originales migrados
└── FormaGeometricaTests.cs      # Tests nuevos (Trapecio, Rectangulo)

Interfaces

IFormaGeometrica

public interface IFormaGeometrica
{
    decimal CalcularArea();
    decimal CalcularPerimetro();
    string ObtenerNombre(IIdioma idioma, int cantidad);
}

IIdioma

public interface IIdioma
{
    string ObtenerEncabezado();
    string ObtenerEncabezadoVacio();
    string ObtenerPalabrasFormas();
    string ObtenerPalabraPerimetro();
    string ObtenerNombreSingular(string forma);
    string ObtenerNombrePlural(string forma);
}

Formas disponibles

Clase Parámetros del constructor
Cuadrado lado
Circulo diametro
TrianguloEquilatero lado
Trapecio baseMayor, baseMenor, altura
Rectangulo ancho, alto

Idiomas disponibles

Clase Idioma
Castellano Español
Ingles Inglés

Uso

var formas = new List<IFormaGeometrica>
{
    new Cuadrado(5),
    new Circulo(3),
    new TrianguloEquilatero(4),
    new Trapecio(6, 4, 3)
};

string reporte = ReporteFormas.Imprimir(formas, new Castellano());

Principios OOP aplicados

Single Responsibility (SRP) — cada clase tiene una única razón para cambiar. ReporteFormas orquesta, las formas calculan geometría, los idiomas traducen.

Open/Closed (OCP) — el sistema está abierto a extensión y cerrado a modificación. Agregar una nueva forma o idioma no requiere tocar ninguna clase existente.

Liskov Substitution (LSP) — cualquier IFormaGeometrica es intercambiable. ReporteFormas no sabe si está procesando un Circulo o un Trapecio.

Strategy Pattern — los idiomas son estrategias intercambiables en runtime. Se pasa la instancia de idioma deseada al momento de generar el reporte.


Cómo agregar una nueva forma

  1. Crear una clase que implemente IFormaGeometrica.
  2. Agregar su nombre singular y plural en el diccionario de cada clase de idioma.
  3. No modificar nada más.
public class Pentagono : IFormaGeometrica
{
    private readonly decimal _lado;
    public Pentagono(decimal lado) { _lado = lado; }

    public decimal CalcularArea()      => (decimal)(Math.Sqrt(25 + 10 * Math.Sqrt(5)) / 4) * _lado * _lado;
    public decimal CalcularPerimetro() => _lado * 5;

    public string ObtenerNombre(IIdioma idioma, int cantidad) =>
        cantidad == 1 ? idioma.ObtenerNombreSingular("Pentagono")
                      : idioma.ObtenerNombrePlural("Pentagono");
}

Cómo agregar un nuevo idioma

  1. Crear una clase que implemente IIdioma.
  2. Completar el diccionario con los nombres de todas las formas.
  3. No modificar nada más.
public class Frances : IIdioma
{
    private static readonly Dictionary<string, (string, string)> _traducciones =
        new Dictionary<string, (string, string)>
        {
            { "Cuadrado",            ("Carré",     "Carrés")    },
            { "Circulo",             ("Cercle",    "Cercles")   },
            { "TrianguloEquilatero", ("Triangle",  "Triangles") },
            { "Trapecio",            ("Trapèze",   "Trapèzes")  },
            { "Rectangulo",          ("Rectangle", "Rectangles")},
        };

    public string ObtenerEncabezado()       => "<h1>Rapport des formes</h1>";
    public string ObtenerEncabezadoVacio()  => "<h1>Liste vide de formes!</h1>";
    public string ObtenerPalabrasFormas()   => "formes";
    public string ObtenerPalabraPerimetro() => "Périmètre";

    public string ObtenerNombreSingular(string forma) =>
        _traducciones.TryGetValue(forma, out var t) ? t.Item1 : forma;
    public string ObtenerNombrePlural(string forma) =>
        _traducciones.TryGetValue(forma, out var t) ? t.Item2 : forma;
}

Tests

El proyecto de tests usa NUnit 4 sobre .NET Framework 4.8.

NUnit                4.6.0
NUnit.ConsoleRunner  3.22.0
NUnit3TestAdapter    6.2.0

Para correr los tests: Test Explorer → Run All o click derecho sobre un test → Debug Test para correr con debugger.

Los tests cubren: lista vacía en los dos idiomas, forma única, plurales, mezcla de tipos, Trapecio, Rectangulo.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages