C# de los fundamentos al dominio — Lección 4
Dividir roles en herencia, interfaces y genéricos
Los artículos escritos en este blog fueron creados con el objetivo de enseñar. Además, la información del artículo puede ser incorrecta, así que tenga cuidado.
La herencia y las interfaces se pueden utilizar cuando varias clases necesitan proporcionar el mismo comportamiento. El tipo de contrato que se presenta al mundo exterior es más importante que vincular cosas en común.
Expresar roles a través de interfaces
public interface IDamageable
{
bool IsAlive { get; }
void TakeDamage(int amount);
}
public sealed class Monster : IDamageable
{
public int Health { get; private set; } = 100;
public bool IsAlive => Health > 0;
public void TakeDamage(int amount)
{
Health = Math.Max(0, Health - amount);
}
}
Para el código de ataque, solo necesitas conocer IDamageable, no todo el Monstruo. Puedes usar el mismo código más adelante para agregar espantapájaros de entrenamiento o cajas destructibles.
La herencia se utiliza en relaciones es-a.
public abstract class Skill
{
public string Name { get; }
protected Skill(string name) => Name = name;
public abstract void Execute(IDamageable target);
}
public sealed class FireSkill : Skill
{
public FireSkill() : base("Fire") { }
public override void Execute(IDamageable target)
{
target.TakeDamage(30);
}
}
La herencia también hereda el estado y las reglas de la clase base. Si crea una estructura de herencia profunda simplemente para reutilizar unas pocas líneas de código, los cambios en el padre afectarán a todos los hijos.
Mantener la seguridad de tipos con genéricos
public sealed class Registry<T> where T : class
{
private readonly Dictionary<int, T> values = new();
public void Add(int id, T value) => values.Add(id, value);
public T? Find(int id)
{
return values.TryGetValue(id, out T? value) ? value : null;
}
}
Registry<Monster> y Registry<Skill> utilizan las mismas reglas de almacenamiento, pero sus valores no se pueden mezclar. La restricción where le dice al compilador qué propiedades debe proporcionar T.
Las interfaces expresan roles, la herencia expresa una base común y los genéricos expresan las mismas reglas para diferentes tipos. En lugar de utilizar muchas de las tres funciones a la vez, es más seguro crear primero el contrato más pequeño y ampliarlo cuando sea necesario.