Introducción: dos caras de la misma moneda
\n\nImagina que estás construyendo una casa. Puedes tomar bloques prefabricados (clases, objetos, herencia) y ensamblarlos en una estructura compleja — esto es la programación orientada a objetos (POO). O puedes pensar como un matemático: "tomo datos, les aplico una función pura y obtengo un nuevo resultado, sin cambiar nada" — esto es la programación funcional.
\n\nEn C# ambas paradigmas conviven de manera sorprendente. Y si escribes en este lenguaje, tarde o temprano te preguntarás: "¿Y si lo estoy haciendo mal? ¿Quizás debería usar más LINQ y menos clases?"
\n\nEn este artículo no discutiremos qué es mejor. Analizaremos en qué se diferencia el enfoque funcional de la POO en C#, cuándo cada uno realmente ayuda y cuándo perjudica. Y sí, habrá mucho código. ¡Allá vamos!
\n\n1. POO en C#: lo clásico que funciona
\n\nLa programación orientada a objetos trata sobre el estado y el comportamiento. Tienes una clase que almacena datos (campos, propiedades) y métodos que modifican esos datos.
Ejemplo: una aplicación para gestionar pedidos en una tienda online.
\n\npublic class Order\n{\n public int Id { get; set; }\n public List<string> Items { get; private set; }\n public decimal TotalPrice { get; private set; }\n\n public Order(int id)\n {\n Id = id;\n Items = new List<string>();\n TotalPrice = 0;\n }\n\n public void AddItem(string itemName, decimal price)\n {\n Items.Add(itemName);\n TotalPrice += price;\n }\n\n public void ApplyDiscount(decimal percent)\n {\n TotalPrice -= TotalPrice * (percent / 100);\n }\n}\n\n¿Qué vemos? Encapsulación: TotalPrice no se puede modificar directamente, solo a través de métodos. Estado del objeto cambia con el tiempo: agregamos productos, aplicamos descuentos. Esto es POO pura.
Ventajas de la POO en C#
\n- \n
- Modelo comprensible del mundo real: Pedido, Cliente, Producto — todo como en la vida real. \n
- Reutilización mediante herencia e interfaces. \n
- Gestión de la complejidad dividiendo en objetos pequeños. \n
Desventajas de la POO
\n- \n
- Efectos secundarios: un método puede cambiar el estado y fácilmente pierdes el control. \n
- Dificultad para probar: hay que crear objetos, simular dependencias. \n
- Redundancia: a veces es más fácil escribir una función que crear toda una clase. \n
2. Enfoque funcional en C#: LINQ y más
\n\nLa programación funcional trata sobre funciones puras (sin efectos secundarios) y la inmutabilidad de los datos. En C# esto es especialmente notable en LINQ, expresiones lambda y el trabajo con colecciones.
\n\nResolvamos la misma tarea — gestionar un pedido — pero de forma funcional.
\n\n// Registro inmutable (record)\npublic record Order(int Id, List<string> Items, decimal TotalPrice);\n\npublic static class OrderFunctions\n{\n public static Order AddItem(Order order, string item, decimal price)\n {\n var newItems = order.Items.Append(item).ToList();\n return order with { Items = newItems, TotalPrice = order.TotalPrice + price };\n }\n\n public static Order ApplyDiscount(Order order, decimal percent)\n {\n return order with { TotalPrice = order.TotalPrice * (1 - percent / 100) };\n }\n}\n\n// Uso\nvar order = new Order(1, new List<string>(), 0);\norder = OrderFunctions.AddItem(order, "Portátil", 50000);\norder = OrderFunctions.ApplyDiscount(order, 10);\n\n¿Te diste cuenta? No modificamos el objeto original. Cada vez se crea una nueva instancia con with. Esto elimina cambios accidentales.
Y