📁 Ubicación sugerida: /home/ubuntu/cafeteria_singleton/CafeteriaSingleton/Program.cs
using System;
using System.Collections.Generic;
namespace CafeteriaSingleton
{
public class Pedido
{
public string Cliente { get; set; }
public string Bebida { get; set; }
public Pedido(string cliente, string bebida)
{
Cliente = cliente;
Bebida = bebida;
}
}
// ❌ Esta clase se instancia cada vez, perdiendo el control central
public class RegistroPedidos
{
private List<Pedido> pedidos = new List<Pedido>();
public void AgregarPedido(Pedido pedido)
{
pedidos.Add(pedido);
Console.WriteLine($"📝 Pedido agregado: {pedido.Cliente} - {pedido.Bebida}");
}
public void MostrarPedidos()
{
Console.WriteLine("📋 Pedidos registrados:");
foreach (var pedido in pedidos)
{
Console.WriteLine($"- {pedido.Cliente}: {pedido.Bebida}");
}
}
}
class Program
{
static void Main(string[] args)
{
// ☠️ Cada barista crea su propio registro
var registroBarista1 = new RegistroPedidos();
registroBarista1.AgregarPedido(new Pedido("Ana", "Latte"));
var registroBarista2 = new RegistroPedidos();
registroBarista2.AgregarPedido(new Pedido("Luis", "Café Americano"));
// ❌ No se ven todos los pedidos, cada uno tiene su propia lista
Console.WriteLine("\nRegistro del barista 1:");
registroBarista1.MostrarPedidos();
Console.WriteLine("\nRegistro del barista 2:");
registroBarista2.MostrarPedidos();
Console.WriteLine("\n¿Dónde está la lista completa? 🤔");
}
}
}Refactorizacion de RegistroPedidos aplicando el patrón Singleton (versión thread-safe con lazy initialization) para que todos los baristas usen la misma instancia compartida.
using System;
using System.Collections.Generic;
namespace CafeteriaSingleton
{
public class Pedido
{
public string Cliente { get; set; }
public string Bebida { get; set; }
public Pedido(string cliente, string bebida)
{
Cliente = cliente;
Bebida = bebida;
}
}
// ✅ Clase Singleton
public class RegistroPedidos
{
private List<Pedido> pedidos = new List<Pedido>();
// 1️⃣ Constructor privado
private RegistroPedidos() { }
// 2️⃣ Instancia estática privada
private static RegistroPedidos _instancia;
// 3️⃣ Objeto para control de concurrencia
private static readonly object _candado = new object();
// 4️⃣ Método público para obtener la instancia
public static RegistroPedidos ObtenerInstancia()
{
lock (_candado)
{
if (_instancia == null)
{
_instancia = new RegistroPedidos();
}
return _instancia;
}
}
public void AgregarPedido(Pedido pedido)
{
pedidos.Add(pedido);
Console.WriteLine($"📝 Pedido agregado: {pedido.Cliente} - {pedido.Bebida}");
}
public void MostrarPedidos()
{
Console.WriteLine("📋 Pedidos registrados:");
foreach (var pedido in pedidos)
{
Console.WriteLine($"- {pedido.Cliente}: {pedido.Bebida}");
}
}
}
class Program
{
static void Main(string[] args)
{
// ✅ Todos los baristas usan la misma instancia
var registroBarista1 = RegistroPedidos.ObtenerInstancia();
registroBarista1.AgregarPedido(new Pedido("Ana", "Latte"));
var registroBarista2 = RegistroPedidos.ObtenerInstancia();
registroBarista2.AgregarPedido(new Pedido("Luis", "Café Americano"));
Console.WriteLine("\nRegistro del barista 1:");
registroBarista1.MostrarPedidos();
Console.WriteLine("\nRegistro del barista 2:");
registroBarista2.MostrarPedidos();
Console.WriteLine("\n🎉 Ahora sí, todos los pedidos están en un solo lugar.");
}
}
}- ¿Qué ventajas trajo el Singleton?
Único punto de acceso Ahora todos los baristas trabajan sobre la misma instancia, por lo que los pedidos se registran en una sola lista compartida.
Consistencia global Evita que existan múltiples "listas de pedidos" separadas que causen confusión. Toda la aplicación consulta el mismo estado.
Control centralizado Si en algún momento quisieras añadir reglas (ej. validar duplicados, aplicar descuentos, logs, etc.), las aplicas en un solo lugar.
Thread-safe (con lock) Gracias al candado (lock), en entornos multihilo se asegura que no se creen dos instancias simultáneamente.
- ¿Hubo alguna limitación? Dificulta pruebas unitarias (testing) Como la clase controla su propia instancia, es complicado sustituirla por un objeto falso (mock) durante pruebas.
Acoplamiento global Cualquier parte de la aplicación puede llamar RegistroPedidos.ObtenerInstancia(). Eso genera dependencia oculta en muchas clases, lo que reduce flexibilidad.
Ciclo de vida poco claro La instancia vive durante toda la ejecución. Si en el futuro quisieras resetear o reiniciar el sistema de pedidos, sería más difícil.
Riesgo de convertirse en “variable global disfrazada” Abusar de Singletons puede terminar ensuciando el diseño con dependencias invisibles y poco controladas.
- ¿Sería mejor usar Dependency Injection en lugar de Singleton? Con Singleton Útil si de verdad existe un recurso que solo debe tener una instancia en toda la aplicación (ejemplo: configuración global, conexión centralizada a logs).
Con Dependency Injection
Puedes decidir en tiempo de ejecución si usas la implementación real o una simulada (mock).
El ciclo de vida de las dependencias se controla explícitamente (ej. Scoped, Singleton, Transient en .NET).
Evita el acoplamiento oculto porque las dependencias se declaran en los constructores.