Dominando la Ingeniería de Software en .NET: UML, SOLID y Patrones de Diseño

Enviado por Chuletator online y clasificado en Informática y Telecomunicaciones

Escrito el en español con un tamaño de 10,53 KB

1. Modelado con Diagramas UML

1.A. Diagrama de Clases

Cómo resolver:

  • Cada class → una clase UML.
  • Atributos → propiedades/campos.
  • Métodos → operaciones.
  • List<T> → relación 1 a muchos.
  • Parámetro de método → dependencia punteada.
  • Herencia : ClasePadre → generalización.

1.B. Diagrama de Secuencia

Este diagrama es frecuente en ejercicios donde se especifica: “desde esta llamada hasta que imprime tal cosa”.

Cómo resolver:

Participantes:

program:Program
manejador:ManejadorOfertas
email:ServicioEmail

Mensajes:

program -> manejador : <<create>>
manejador -> email : <<create>>
program -> manejador : NotificarClientes(clientes)
loop [por cada cliente]
manejador -> email : SendEmail(user.Email, message)

1.C. Diagrama de Paquetes

Se identifica habitualmente mediante el uso de namespace.

Ejemplo:

namespace Domain
namespace Notificador
namespace InterfazUsuario

Solución:

InterfazUsuario - - - -> Domain
Domain - - - -> Notificador

Justificación: Program utiliza el dominio y el dominio utiliza el notificador.

2. Principios SOLID

SRP — Single Responsibility (Responsabilidad Única)

Una clase debe tener un solo motivo de cambio.

Cómo identificarlo: La clase realiza varias tareas distintas.
Violación: Viola el SRP porque concentra varias responsabilidades y puede verse obligada a cambiar por más de un motivo.

OCP — Open/Closed (Abierto/Cerrado)

El software debe estar abierto para su extensión, pero cerrado para su modificación.

Cómo identificarlo: Presencia de estructuras if, else if o switch basadas en tipos.
Violación: Viola el OCP porque agregar un nuevo tipo obliga a modificar el código existente en lugar de extenderlo.

LSP — Liskov Substitution (Sustitución de Liskov)

Una subclase debe poder reemplazar a su clase padre sin alterar el funcionamiento del programa.

Cómo identificarlo: Una clase hija hereda un comportamiento que no puede cumplir o lanza excepciones de "no implementado".
Violación: Viola el LSP porque la subclase no respeta el contrato esperado de la clase base.

ISP — Interface Segregation (Segregación de Interfaces)

Ningún cliente debería ser obligado a depender de métodos que no utiliza.

Cómo identificarlo: Interfaces "gigantes" con demasiados métodos.
Violación: Viola el ISP porque obliga a las clases a implementar métodos que no necesitan.

DIP — Dependency Inversion (Inversión de Dependencias)

Las clases de alto nivel no deben depender de clases de bajo nivel (concretas), sino de abstracciones.

Cómo identificarlo: Se observa el uso de new para instanciar un servicio concreto dentro de una clase.
Violación: Viola el DIP porque la clase depende directamente de una implementación concreta. Se corrige dependiendo de una interfaz e inyectando la implementación.

3. Patrones de Diseño

Singleton

Se aplica en escenarios de única conexión, único contador o generador centralizado.

Palabras clave: “única instancia”, “números duplicados”, “una sola conexión”, “un único canal”.

Definición: Es un patrón creacional cuya intención es asegurar una única instancia de una clase y proveer un punto global de acceso a ella.

Factory Method

Común en ejercicios de creación de vehículos o entidades según un tipo específico.

if (tipo == "Auto") return new Auto(); else if (tipo == "Camion") return new Camion();

Definición: Es un patrón creacional que permite delegar la creación de objetos concretos a subclases o métodos especializados.

Facade (Fachada)

Se utiliza cuando una pantalla o componente debe interactuar con múltiples servicios complejos.

_orders.Confirm(id); _pay.Capture(id); _ship.CreateLabel(id);

Definición: Es un patrón estructural que provee una interfaz simplificada para coordinar varios subsistemas.

Template Method

Se aplica cuando existen pasos comunes en un proceso pero con partes variables.

Palabras clave: “mismo algoritmo”, “código duplicado”, “pasos comunes”, “partes que cambian”.

Definición: Es un patrón de comportamiento que define el esqueleto de un algoritmo en una clase base, delegando los pasos variables a las subclases.

Strategy

Aunque es menos explícito, suele aparecer relacionado con el principio OCP.

Identificación: Un if que decide un comportamiento o algoritmo, no una creación de objeto.

4. TDD y Testing

Fases del TDD (Test Driven Development)

El TDD consiste en un ciclo de tres pasos:

  1. Escribir primero una prueba unitaria que falle (Rojo).
  2. Escribir el código mínimo necesario para que la prueba pase (Verde).
  3. Refactorizar el código sin alterar su comportamiento.

Nota importante: No se puede determinar si se usó TDD solo mirando el código final. La existencia de tests no garantiza TDD, ya que pudieron escribirse a posteriori.

Estructura de un Test: Arrange (preparar), Act (ejecutar) y Assert (verificar).

Errores Comunes: NullReference en Tests

private Producto producto;
[TestMethod]
public void Precio_DeberiaSerCeroPorDefecto() {
    Assert.AreEqual(0, producto.Precio);
}

Este test falla porque el objeto producto nunca fue inicializado. Se corrige utilizando el atributo [TestInitialize] para instanciar los objetos antes de cada prueba.

Fakes y Test Doubles

Se utilizan para eliminar dependencias externas como la hora del sistema, bases de datos o servicios de correo.

public interface IClock { DateTime UtcNow { get; } }
public class FakeClock : IClock { public DateTime UtcNow { get; set; } }

5. Entity Framework (EF) y ORM

¿Qué es EF / ORM? Entity Framework es un mapeador objeto-relacional (ORM) que permite interactuar con datos utilizando objetos del dominio en lugar de escribir consultas SQL manualmente.

  • Code First: Se definen primero las clases en C# y luego se genera la base de datos.
  • Database First: Se parte de una base de datos existente para generar las clases.
  • DbContext: Representa la sesión de trabajo con la base de datos.
  • DbSet<T>: Representa una tabla o colección de entidades.

Estrategias de Carga

  • Eager Loading: Utiliza el método .Include() para cargar datos relacionados en una sola consulta.
  • Lazy Loading: Carga los datos relacionados automáticamente al acceder a la propiedad de navegación.
  • Explicit Loading: Los datos se cargan manualmente mediante el uso de Entry().Load().

Fluent API: Permite configurar el modelo de Entity Framework mediante código dentro del método OnModelCreating.

Estrategias de Herencia en Base de Datos

  • TPH (Table Per Hierarchy): Una sola tabla para toda la jerarquía. Incluye una columna Discriminator. Se elige para lecturas rápidas y cuando se listan tipos mezclados frecuentemente.
  • TPT (Table Per Type): Una tabla para la clase padre y tablas adicionales para las hijas. Se elige para una normalización estricta sin duplicación de datos.
  • TPC (Table Per Concrete Class): Una tabla por cada clase concreta, repitiendo atributos comunes. Se elige cuando se consulta principalmente por un tipo concreto específico.

6. DTO y Desarrollo con Blazor

DTO (Data Transfer Object)

Se utiliza frecuentemente con entidades de usuario y flujos de entrada/salida de datos.

Definición: Un DTO transporta datos entre capas y evita exponer directamente las entidades del dominio.

Ventajas:

  • Seguridad mejorada.
  • Desacoplamiento entre la UI y el Dominio.
  • Evita exponer datos sensibles (como passwords).
  • Optimiza la transferencia enviando solo lo necesario.

Blazor y Dependencias

  • @page: Define la ruta del componente.
  • @inject: Inyecta un servicio registrado en el contenedor de dependencias.

El registro debe realizarse en Program.cs: builder.Services.AddScoped<IUsuariosService, UsuariosService>();

Ciclos de Vida en Inyección de Dependencias (DI)

  • Transient: Se crea una nueva instancia cada vez que se solicita.
  • Scoped: Una instancia por cada alcance o circuito (ideal para servicios que usan EF, ya que evita compartir estado global entre usuarios).
  • Singleton: Una única instancia global para toda la aplicación.

7. Arquitectura y Ecosistema .NET

  • Assembly: Unidad lógica de compilación, versionado y reutilización (archivos .dll o .exe).
  • CLR (Common Language Runtime): El entorno de ejecución de .NET. Gestiona el código intermedio, la memoria, las excepciones y el Garbage Collector.
  • BCL (Base Class Library): Biblioteca de clases base de .NET que incluye System, colecciones, manejo de archivos, fechas, etc.
  • Namespace: Estructura que organiza las clases y evita conflictos de nombres entre ellas.

Entradas relacionadas: