using System;
using System.Collections.Generic;
namespace GranjaInteligente
{
// FACTORY METHOD
// Creamos una clase abstracta para Dieta
public abstract class Dieta
{
public abstract void Alimentar();
}
// Implementaciones concretas de dieta por animal
public class DietaVaca : Dieta
{
public override void Alimentar()
{
Console.WriteLine("Dando heno, agua y sal mineral a la vaca.");
}
}
public class DietaCerdo : Dieta
{
public override void Alimentar()
{
Console.WriteLine("Dando granos y jugo al cerdo.");
}
}
public class DietaGallina : Dieta
{
public override void Alimentar()
{
Console.WriteLine("Dando semillas y agua a la gallina.");
}
}
// Factory Method: clase base
public abstract class DietaFactory
{
public abstract Dieta CrearDieta();
}
// Factorías concretas
public class DietaVacaFactory : DietaFactory
{
public override Dieta CrearDieta() => new DietaVaca();
}
public class DietaCerdoFactory : DietaFactory
{
public override Dieta CrearDieta() => new DietaCerdo();
}
public class DietaGallinaFactory : DietaFactory
{
public override Dieta CrearDieta() => new DietaGallina();
}
// ABSTRACT FACTORY
// Familia de productos: Alimento, Bebida, Suplemento
public interface IAlimento { void Mostrar(); }
public interface IBebida { void Mostrar(); }
public interface ISuplemento { void Mostrar(); }
// Productos concretos para Vaca
public class Heno : IAlimento { public void Mostrar() => Console.WriteLine("Alimento: Heno"); }
public class Agua : IBebida { public void Mostrar() => Console.WriteLine("Bebida: Agua"); }
public class SalMineral : ISuplemento { public void Mostrar() => Console.WriteLine("Suplemento: Sal mineral"); }
// Productos concretos para Cerdo
public class Granos : IAlimento { public void Mostrar() => Console.WriteLine("Alimento: Granos"); }
public class Jugo : IBebida { public void Mostrar() => Console.WriteLine("Bebida: Jugo"); }
public class SuplementoCerdo : ISuplemento { public void Mostrar() => Console.WriteLine("Suplemento: Vitaminas porcinas"); }
// Productos concretos para Gallina
public class Semillas : IAlimento { public void Mostrar() => Console.WriteLine("Alimento: Semillas"); }
public class AguaGallina : IBebida { public void Mostrar() => Console.WriteLine("Bebida: Agua fresca"); }
public class Calcio : ISuplemento { public void Mostrar() => Console.WriteLine("Suplemento: Calcio"); }
// Abstract Factory
public interface IAnimalFactory
{
IAlimento CrearAlimento();
IBebida CrearBebida();
ISuplemento CrearSuplemento();
}
// Factorías concretas
public class VacaFactory : IAnimalFactory
{
public IAlimento CrearAlimento() => new Heno();
public IBebida CrearBebida() => new Agua();
public ISuplemento CrearSuplemento() => new SalMineral();
}
public class CerdoFactory : IAnimalFactory
{
public IAlimento CrearAlimento() => new Granos();
public IBebida CrearBebida() => new Jugo();
public ISuplemento CrearSuplemento() => new SuplementoCerdo();
}
public class GallinaFactory : IAnimalFactory
{
public IAlimento CrearAlimento() => new Semillas();
public IBebida CrearBebida() => new AguaGallina();
public ISuplemento CrearSuplemento() => new Calcio();
}
// BUILDER
public class RutinaAlimentacion
{
public List<string> Pasos { get; set; } = new List<string>();
public void MostrarRutina()
{
Console.WriteLine("=== Rutina de alimentación ===");
foreach (var paso in Pasos)
Console.WriteLine(paso);
}
}
public interface IRutinaBuilder
{
void PrepararDesayuno();
void PrepararSnack();
void PrepararCena();
RutinaAlimentacion ObtenerRutina();
}
public class RutinaVacaBuilder : IRutinaBuilder
{
private RutinaAlimentacion rutina = new RutinaAlimentacion();
public void PrepararDesayuno() => rutina.Pasos.Add("Desayuno: Heno + Agua");
public void PrepararSnack() => rutina.Pasos.Add("Snack: Sal Mineral");
public void PrepararCena() => rutina.Pasos.Add("Cena: Heno + Agua");
public RutinaAlimentacion ObtenerRutina() => rutina;
}
public class RutinaDirector
{
public RutinaAlimentacion Construir(IRutinaBuilder builder)
{
builder.PrepararDesayuno();
builder.PrepararSnack();
builder.PrepararCena();
return builder.ObtenerRutina();
}
}
// PROTOTYPE
public class RutinaPrototype : ICloneable
{
public RutinaAlimentacion? Rutina { get; set; }
public object Clone()
{
return new RutinaPrototype
{
Rutina = new RutinaAlimentacion { Pasos = new List<string>(Rutina!.Pasos) }
};
}
}
// SINGLETON THREAD-SAFE
public class RegistroGlobalAlimentacion
{
private static readonly object _lock = new object();
private static RegistroGlobalAlimentacion? instancia;
private RegistroGlobalAlimentacion() { }
public static RegistroGlobalAlimentacion Instancia
{
get
{
if (instancia == null)
{
lock (_lock)
{
if (instancia == null)
instancia = new RegistroGlobalAlimentacion();
}
}
return instancia;
}
}
public void Registrar(string mensaje)
{
Console.WriteLine($"[REGISTRO] {mensaje}");
}
}
// MAIN PROGRAM
public class Program
{
public static void Main(string[] args)
{
// FACTORY METHOD
DietaFactory dietaFactory = new DietaVacaFactory();
var dieta = dietaFactory.CrearDieta();
dieta.Alimentar();
// ABSTRACT FACTORY
IAnimalFactory factory = new VacaFactory();
factory.CrearAlimento().Mostrar();
factory.CrearBebida().Mostrar();
factory.CrearSuplemento().Mostrar();
// BUILDER
var director = new RutinaDirector();
var rutinaBuilder = new RutinaVacaBuilder();
var rutina = director.Construir(rutinaBuilder);
rutina.MostrarRutina();
// PROTOTYPE
var prototipo = new RutinaPrototype { Rutina = rutina };
var rutinaClonada = (RutinaPrototype)prototipo.Clone();
rutinaClonada.Rutina!.MostrarRutina();
// SINGLETON
var registro = RegistroGlobalAlimentacion.Instancia;
registro.Registrar("Ciclo de alimentación completado.");
}
}
}Factory Method (reemplaza FeedingSystem) Antes: if/else gigante en FeedingSystem. Ahora: Cada dieta se crea con su propia factoría (DietaVacaFactory, DietaCerdoFactory, DietaGallinaFactory).
Abstract Factory Antes: No existía separación de familias de productos. Ahora: IAnimalFactory produce familias consistentes (Alimento, Bebida, Suplemento).
Builder Antes: No había construcción paso a paso de rutinas. Ahora: RutinaDirector construye rutinas completas con RutinaVacaBuilder.
Prototype Antes: Cada rutina debía configurarse manualmente. Ahora: Se pueden clonar rutinas previas (RutinaPrototype) para ahorrar configuración.
Singleton (corregido) Antes: RegistroAlimentacion no era thread-safe. Ahora: RegistroGlobalAlimentacion usa double-checked locking para seguridad en multihilo.
- El método Alimentar(string animal) dependía de cadenas de texto.
- Si había un error tipográfico ("vaca" en minúscula, por ejemplo), no funcionaba.
- Violaba el principio OCP (Open/Closed Principle): cada nuevo animal obligaba a modificar la clase.
- No existía encapsulación de la lógica de alimentación por animal.
- No era thread-safe: en entornos concurrentes podían crearse varias instancias.
- No había bloqueo (lock) ni control de acceso simultáneo.
- Violaba el SRP (Single Responsibility Principle): mezclaba lógica de creación con registro de logs.
- Toda la lógica estaba embebida en unas pocas clases.
- No había abstracciones para representar dietas, alimentos, bebidas o suplementos.
- Esto dificultaba la extensión del sistema (ej. agregar caballos, ovejas, etc.).
- Los alimentos, bebidas y suplementos estaban “hardcodeados” dentro de strings.
- Si se quisiera cambiar qué consume cada animal, había que modificar código en lugar de extenderlo.
- No existía un patrón de construcción paso a paso (Builder).
- Las rutinas de alimentación estaban implícitas en Console.WriteLine, sin posibilidad de reusarlas o configurarlas dinámicamente.
- No había un Prototype para clonar rutinas previas.
- Cada rutina debía escribirse de cero aunque fuera muy similar a otra.
💬 Retroalimentación – Antonio
Práctica: Granja Creacional (Patrones de Diseño Creacionales – GoF)
Calificación: 85 / 100
Buen trabajo, Antonio. Se nota un esfuerzo claro por comprender y aplicar los patrones creacionales en el contexto de una granja automatizada.
Tu código incluye implementaciones correctas de Factory Method, Abstract Factory, Builder, Prototype y Singleton, lo cual cumple de forma completa con los requisitos de la práctica.
Además, es positivo que incluyas comentarios sobre los cambios realizados y problemas del código original, mostrando reflexión sobre el proceso de diseño.
Como primera práctica, el resultado es muy bueno. Para futuras entregas, podrías mejorar en:
Integrar los patrones en un flujo funcional más cohesivo.
Incluir más documentación interna (comentarios sobre decisiones de diseño).
Agregar validaciones o pruebas que demuestren el funcionamiento con distintos escenarios.
En general, se cumple el objetivo principal: entender y aplicar los patrones creacionales de manera práctica y estructurada.
Sigue con este nivel de detalle, solo reforzando la explicación técnica y la integración entre componentes.
Puntaje final: 85 / 100
10 puntos con el agregado Asciinema da 95..