Mostrando entradas con la etiqueta herencia. Mostrar todas las entradas
Mostrando entradas con la etiqueta herencia. Mostrar todas las entradas

domingo, 2 de marzo de 2008

Herencia múltiple en C# ( resuelta )

Bueno, en realidad no, no hay forma de resolver el tema de la herencia múltiple en C# sin modificar el lenguage, pero siempre podemos acceder a soluciones alternativas mas o menos funcionales para lograr los mismos resultados que queríamos obtener con la herencia múltiple.

Estas soluciones alternativas dependen en general de los medios que poseemos y los resultados esperados. En muchos casos el problema es que tenemos una clase utilitaria que espera objetos de un tipo determinado ( no una interface ), para que nuestro objeto pueda ser utilizado en ese contexto heredamos de aquel y listo:


// Este es el tipo que se usa en la clase utilitaria
public class Usable
{
public virtual void HacerAlgo()
{
Console.WriteLine("Hice algo");
}
}

// Esta es la clase utilitaria
public class Utilitaria
{
public void Usa(Usable u)
{
u.HacerAlgo();
}
}

// Y este es nuestro tipo
class NuestroTipo : Usable
{
public override void HacerAlgo()
{
Console.WriteLine("Hacer otra cosa");
}
}

Hasta aqui todo bien. Pero que pasa si nuestro tipo ya heredaba de otro ? Si hubiera herencia múltiple heredábamos de Usable y de nuestro tipo base pero como no hay siempre podemos instanciar un objeto de tipo Usable y publicarlo para luego usarlo:


class NuestroTipo : NuestroTipoBase
{
private Usable m_usa = new Usable();
public Usable Usar { get { return m_usa; } }
}

...

Utilitaria util = new Utilitaria();
NuestroTipo tipo = new NuestroTipo();
util.Usa(tipo.Usar);

Evidentemente este ejemplo tiene una falla fundamental: esto no tiene nada que ver con la herencia. Si queríamos usar la herencia es porque probablemente hay algo dentro del tipo Usable que queríamos reescribir asi que simplemente instanciarlo dentro del nuestro no resuelve ningún problema. Al final lo que queremos es redefinir el comportamiento del tipo Usable y además queremos en esta redefinición haga uso de las interioridades de nuestro tipo. La solución es crear una clase interna que herede del tipo Usable y que redefina lo que sea necesario, además sería necesario siempre pasarle una instancia de nuestro objeto para poder tener acceso a sus interioridades. Algo asi:


// Este es nuestro tipo que hereda de otro
public class NuestroTipo : NuestroTipoBase
{
// Este es nuestro usable interno
private class NuestroUsable : Usable
{
// Evidentemente necesitamos acceder a las
// interioridades del objeto master
NuestroTipo m_master;
public NuestroUsable(NuestroTipo master)
{
m_master = master;
}
public override void HacerAlgo()
{
Console.WriteLine("Hacer otra cosa ( internamente )");
}
}
private readonly NuestroUsable m_usa;
public Usable Usar { get { return m_usa; } }
public NuestroTipo()
{
m_usa = new NuestroUsable(this);
}
}

Esto resuelve el problema en parte, aunque nos deja todavía con la necesidad de instanciar el objeto, cosa que además tiene que hacerse en el constructor ya que no nos permiten instanciarlo en la declaración pasándole además this como parámetro.

Lo mejor evidentemente sería tener herencia múltiple nativa en el lenguage pero como no hay podemos acudir a este tipo de mecanismos para simularla cuando la necesidad se presenta.

viernes, 29 de febrero de 2008

Herencia múltiple

C# no tiene herencia múltiple, Java tampoco, Delphi tampoco. De los lenguages mas usados solo C++ tiene herencia múltiple y en la mayoría de los programas que he visto no es usada. Sin embargo es una de las características que mas extraño en mi viaje por .NET desde C++ porque ayuda a resolver muchos problemas. Me he encontrado conque quiero que una clase sea un componente por el uso que le voy a dar ( hereda de System.ComponentModel.Component ) pero además quiero que se beneficie de un mecanismo de persistencia que he creado. Al final terminas por hacer magia para que el mecanimo no heredado sea capaz de adivinar de todo ( reflection mediante ) o te creas una interface.

El método socorrido de la interface tiene la desventaja de que tienes que implementar los métodos de esta. En muchos casos instancias dentro de la clase un objeto que va a hacer el trabajo y los métodos de la interface solo llaman a los métodos de ese objeto pero esa solución es extremadamente trabajosa si la interface tiene varios métodos.

Sería interesante que se pudiera "delegar" en un objeto. Me gustaría poder hacer automáticamente lo que tanto he tenido que hacer a mano. Decirle al compilador que los métodos de la interface son implementados por un objeto de la clase. Eso en parte se puede lograr en .NET 3 con los métodos de extensión, pero solo en parte, se puede tener la funcionalidad agregada a la clase pero no se pueden aprovechar las ventajas de la herencia. Una solución podría ser en la definición de la clase decir como hasta ahora:

class Ejemplo : IEjemploInterface

pero cuando se declare el objeto interno que implementa los métodos de la interface decir algo como:

implements IEjemploInterface ObjetoInterface obj;

para decir que los llamados a los métodos de la interface se "delegan" en la instancia de ese objeto. Eso sería muy útil ... y me resolvería muchos problemas.