15 enero, 2010

Force to implement a function with a default behaviour

Hoy, mientras refactorizava una parte de un código, he llegado a un punto en el que necesitaba crear una función en una clase, la cual tenia que ser de implementación obligada, pero sólo una parte de su código.
Añadido, necesitaba que se hiciera ésta implementación tipificada, dado que ese desarrollo tenían que implementar-lo muchas clases distintas.

Resumiendo:
- Necesitaba una clase base
- Un código que se forzada su implemnetación en sus hijos
- Permitir añadir código a la clase base, de manera que no tuviera que modificar las hijas.

¿Cómo? (cuando descubro ésta parte es cuando entiendo porqué la arquitectura de software puede encajar mágicamente tantas piezas y comportamientos)

abstract class BotellaFundamentals
{
public virtual void AbrirBotella()
{
// Espacio para un futuro
// Si ésta clase fuera real, probablemente sería mucho más genérica,
//por lo que previamente se realizaría un acceso a un controlador: ControlladorInstrumentos de Ibotella...

AbrirTapón();

// Espacio para cambiar en un futuro si se precisa
}

abstract protected void AbrirTapon();
}

class Botella : BotellaFundamentals
{
protected override void AbrirTapon()
{
// Implementación de abrir el tapon de la botella, o sea, ABRIR LA BOTELLA
}
}

Ventajas:
- Todo el mundo puede pedir que se abra la botella.
- Nadie sabe que se consigue abriendo el tapón, simplemente
- Si un dia inventan botellas con 5 tapones, el público no se va enterar, ya que todo el mundo llama a AbrirBotella();
Los cambios que supondrá será que sus clases hijas OBLIGATORIAMENTE deberán implementar la apertura de los otros 4 tapones.

Creo que es un apunte muy simple y aporta muchísimo a una solución.

1 comentario:

eiximenis dijo...

Marc,
Siendo ya quisquilloso, probablemente AbrirBotella NO debería ser virtual. Hay gente que defiende que los métodos públicos nunca deberían ser virtuales, que en caso de necesitarse eso, es mejor pasar la llamada a un método protegido y que sea ese el virtual. El razonamiento que hay tras esto, es que no debería poder permitirse a clases hijas cambiar la semántica de la interfaz definida por la clase base (lo sé... me explico fatal :p).
Aplicado a tu ejemplo: Podemos permitir a cada clase hija que defina como es AbrirTapon pero NO deberíamos permitir redefinir AbrirBotella, porque si no una clase hija puede reimplementar todo el método y EN ESE CASO tu tercer punto no se cumpliria, ya que un buen dia añadirías código a AbrirBotella de la clase base, y ese código NO se ejecutaría en aquella clase que redefinió dicho método :)

Saludos!