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 InterfazUsuarioSolució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:
- Escribir primero una prueba unitaria que falle (Rojo).
- Escribir el código mínimo necesario para que la prueba pase (Verde).
- 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
.dllo.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.