Lo básico parte 3: Herencia

Uno de los pilares de la programación orientada a objetos, es la herencia o la capacidad de crear jerarquías de objetos que van refinando o modificando cierto comportamiento.  Por ejemplo, imaginemos una empresa que vende artículos para el hogar. Imaginemos que vende lavadoras, estufas y licuadoras. Para motivar a sus vendedores, han puesto un sistema de comisiones que funciona de la siguiente manera:

Todos los vendedores tienen una cuota de ventas. Si el 25% de las ventas son por lavadoras, el vendedor obtiene una comisión del 15% de su salario. Si logra al menos el 50% de su comisión con la venta de licuadoras, entonces recibe una comisión del 30% de su salario. Por ultimo si logra el 25% de su cuota vendiendo estufas obtiene una comisión del 20% de su salario.

Ahora, supongamos que estos vendedores están distribuidos en zonas norte, este y sur. Los vendedores de la zona sur tienen una comisión adicional de 10% si exceden la cuota de ventas.

Podríamos representarlo de la siguiente manera:

Herencia

Entonces tenemos una clase CalculadoraComisiones. Los objetos de esta clase contienen toda las reglas para calcular las comisiones de cualquier vendedor. Una forma de implementar esto podría ser algo como:

public interface Vendedor
{
   bool CumplePorcentajeVenta(double porcentaje, string producto);
}


public class CalculadoraComisiones
{
  public virtual decimal CalcularComisiones(Vendedor vendedor)
  {
	  decimal comision = 0;
	  comision = comisionPorLavadoras(vendedor);
	  comision += comisionPorLicuadoras(vendedor);
	  comision += comisionPorEstufas(vendedor);
	  
	  return comision;
  }
  ...
}

Sin embargo para los vendedores de la zona sur, tenemos una regla adicional a las de todos los demás.

public class CalculadoraComisionesZonaSur:CalculadoraComisiones
{
   override CalcularComisiones(Vendedor vendedor)
   {
	   decimal comision = base.CalcularComisiones(vendedor);
	   comision + = comisionPorSobreVenta(vendedor);
	   return comision;
   }
   ...
}

Listo. Solo hay que utilizar el objeto correcto para calcular las comisiones.

void main(){
   List<Vendedor> vendedores = obtenerVendedores("Norte");
   vendedores.AddRange(obtenerVendedores("Este"));
   
  List<Vendedor>vendedoresSur = obtenerVendedores("Sur");
 

  var calculadora = new CalculadoraComisiones();
  for each(var vendedor in vendedores)
 {
    decimal comision = calculadora.CalcularComision(vendedor);
    Console.WriteLine(comision);
 }

  calculadora = new CalculadoraComisionesZonaSur();
 for each(var vendedor in vendedoresSur)
 {
  decimal comisiones = calculadora.CalcularComision(vendedor);
  Console.WriteLine(comision);
 }
}

Sencillo. Definitivamente este código deja mucho que desear pero ya lo iremos ajustando mas adelante.

Ahora quisiera señalar que no hay ninguna propiedad en el diagrama o en el código.
Hice esto deliberadamente para hacer énfasis en un principio fundamental: Se hereda el comportamiento, no los datos. En otras palabras usamos herencia cuando tenemos un objeto que tiene un método que queremos ajustar un poco a nuestras necesidades, no cuando queremos reutilizar datos. Eso es un error muy común. Viene de la mentalidad utilizada en las bases de datos relacionales, en la que se trata de reducir la duplicación de datos. En el caso de la programación orientada a objetos, se trata de reducir la duplicación de métodos. No tengan miedo de repetir datos en diferentes objetos.

Pues eso es todo por hoy, la próxima vez veremos el significado de la frase «favorecer composición sobre herencia» y como eso puede ayudarnos a mejorar el código de este ejemplo. Hasta entonces.