sobre herencia multiple

11/04/2005 - 19:58 por olopeich | Informe spam
Epa!

Tengo un problema q no se como enfocar; es mas bien teorico, ahi va:

Tengo una aplicacion con clientes, cada cliente es un objeto con sus
propiedades metodos y tal.

En un momento dado tengo q representar esos clientes con un treeview. Lo
que hago es derivar una clase de TreeNode llamada mTreeNode donde añado
las propiedades que me interesan de la clase clientes; de este modo
cuando hago click en un nodo del arbol tengo acceso a todos los datos de
ese cliente, q visualizo o manipulo con ayuda de otros controles. Hasta
aqui vamos bien... o mejor dicho medio bien porque al no tener herencia
multiple (es la unica manera q se me ocurre de resolver el problema) no
puedo hacer un

class mTreenode
inherits Treenode, Clientes

.
.
.

End class

porque evidentemente mTreeNode tiene q heredar de Treenode, sino el
treeview peta. De esta guisa tengo q duplicar todo el codigo de clientes
en la clase mTreeView q me interese en vez de simplemente heredar.

Si mas adelante tengo otra representacion distinta de Cliente (yo q se,
con listbox por ejemplo) tengo q volver a hacer lo mismo: crear otra
clase que herede del tipo de dato que ese control pida y duplicar todo
el codigo de Cliente en esa clase.

Y digo yo: hay alguna manera mas elegante de resolver esto en vb .net???
me da la impresion de estar obviando algo muy basico pero no atino...

Saludos y mil gracias a todos.

Preguntas similare

Leer las respuestas

#6 floyd303
12/04/2005 - 21:29 | Informe spam
A ver... yo lo que haria seria guardar una referencia al objeto
cliente (o el objeto cliente entero todo depende del diseño en cada
objeto TreeNode).
Lo que pasa es que el objeto TreeNode en si esta bastante limitado
segun viene... pero es lo bueno de la OOP, que se puede ir haciendo
mas concreto segun lo necesitemos.
Yo haria una clase que heredara de TreeNode, pero que contuviese un
objeto cliente (o una referencia a el).

Por ejemplo:

Public Class TreeNodeCliente
Inherits TreeNode

Protected m_objCliente As Cliente
Public Property Cliente() As Cliente
Get
Return m_objCliente
End Get
Set(ByVal Value As Cliente)
m_objCliente = Value
End Set
End Property

Public Sub New(ByVal objCliente As Cliente)
objCliente = m_objCliente
End Sub
End Class

Pues esta clase la puedes tratar como si de un TreeNode normal y
corriente se tratase.

Dim nodo As TreeNodeCliente
nodo = New TreeNodeCliente (objCliente) ' Le paso el objeto
cliente que representa este nodo
nodo.Text = objCliente.Nombre ' Suponiendo que Cliente tiene
una propiedad llamada Nombre
TreeView1.Nodes.Add(nodo) ' Anado el nodo al TreeView

De esta manera, cuando se seleccione el nodo, podre obtener a su vez
el cliente que contiene dicho nodo:

Private Sub TreeView1_AfterSelect(ByVal sender As Object, ByVal e
As System.Windows.Forms.TreeViewEventArgs) Handles
TreeView1.AfterSelect
Dim nodo As TreeNodeCliente

nodo = TreeView1.SelectedNode
If (nodo Is Nothing) = False Then
MsgBox(nodo.Cliente.Nombre)
End If
End Sub

Puede que el objeto Cliente ocupe bastante memoria y no es plan de
rellenar el TreeView con cada objeto cliente cargado en memoria.
Entonces lo que se podria hacer es guardar, por ejemplo, un
identificador unico del cliente. De esta manera no obtendrias el
objeto cliente entero, pero si una referencia al cliente que han
seleccionado, lo que en el fondo es lo mismo.

Como ves, la herencia multiple es absolutamente innecesaria. Lo que
ocurre con la herencia multiple es que crea mas problemas que
beneficios. Es muy dificil encontrar un escenario en el que la
herencia multiple encaje perfectamente y sea realmente util.

Espero que todo esto te ayude!!
Roberto M. Oliva




olopeich wrote in message news:...
muchas gracias por responder Tristan. Te comento entre lineas. Adelanto
q soy muy inexperto en estos temas. Llevo progrando muchos años pero
pertenezco a la vieja escuela de la programacion estructurada

> Bueno, en general la herencia múltiple no suele ser muy recomendable. Además
> de los problemas que genera, en tu caso no vería mucho sentido en que un
> objeto sea a la vez Cliente y TreeNode. Demasiado diferentes. Yo más bien
> diria que tienes un objeto cliente que SE REPRESENTA mediante un TreeNode.
> Es decir, tu objeto contiene, referencia, un objeto treenode.

mmmm, si, esa seria la idea... pero no veo la manera de implementarlo.
Que hago, en mi clase cliente añado una propiedad de tipo treenode? no
se como voy a poder usar todo esto a la hora de componer el treeview. Y
luego esta el caso de q si tengo varias representaciones de un mismo
cliente a lo largo de la aplicacion, lease, un treeview, un listview, un
combobox... que tendria q hacer, dentro de la clase cliente añadir
referencias a todos los controles (o tipos de dato q esperen esos
controles) q vaya a utilizar?

> Es decir, tu cliente puede crear en su constructor, o cuando sea necesario,
> un objeto TreeNode, y puede visualizarlo dentro de un TreeView asociado.

podrias explicarme un poco la forma de hacer esto? Yo este tipo de
esquema lo utilizo en el siguiente escenario: tengo un treeview con
nodos q son clientes, hago click en uno de ellos y se me devuelve una
clase derivada de treenode q contiene ademas de la info basica del
treenode toda la info del cliente en este caso. Pero no veo como hacer
eso mismo añadiendo una referencia a un treenode desde mi clase cliente...

Y ademas, no estamos en este caso mezclando cosas? quiero decir,
prefiero mantener mi clase cliente limpia de codigo relativo al
interface y derivar una nueva ya 'sucia'... de este modo la clase
original cliente queda impoluta.

> Pero incluso este caso, estaría en contra de un diseño correcto en tres
> capas, puesto que estarías uniendo capa de negocio y de interface en un
> mismo objeto. Todo depende de que quieras seguir esas reglas de diseño. Pero
> aplicando herencia múltiple aún sería mayor la infracción.

lo veo, pero sigo sin tener demasiado claro como implementar esto de
forma medio elegante. Ni siquiera se si esta practica es comun. Pero
sino... como debe de hacerse? hacia pensando mantener en memoria un
arraylist equivalente a la representacion del treeview con todos lso
datos q necesito pero no creo q esta sea la manera de implementar.

Aqui me surge otra duda cosmica: el uso del interfaz como simple
'representador' del estado de la aplicacion vs. el interfaz como
representador y contenedor de datos. Yo el treeview a parte de
representar a los datos de la aplicacion lo uso como contenedor... esto
es correcto? a mi me da q no, pero facilita el desarrollo un huevo...

> Por otro lado, no olvides que aunque .net no admite herencia múltiple de
> implementación, si admite herencia múltiple de interface. Tu objeto puede
> heredar de TreeNode e implementar la interface que necesite de Cliente.

bueno, el tema de las interfaces es q nunca lo he entendido. Iba a
preguntarlo en otro hilo pero ya q estamos... :)

Yo lo de las interfaces no veo su utilidad: si digo q el objeto
miTeeeNode implementa las interfaces tal y cual de la clase cliente...
eso quiere decir q me veo obligado a 'rellenar' esas interfaces no?
osea, no hereda el codigo de cliente sino que segun pone en todos los
libros 'es un contrato' por el cual tengo la obligacion de implemementar
(escribir, o en este caso copiar-pegar) el codigo q implemento.

No se si me he explicado.


> Para mi, la mejor solución es o bien la que te dije al principio, o incluso
> un diseño en que se separe negocio e interface. Una clase para
> representación visual del cliente (heredada de TreeNode) y otra con las
> reglas del cliente, que herede de la clase que necesites, tal vez Persona.

Esta es la forma en la q lo tengo hecho, pero claro, duplico codigo (las
partes q me interesan de Cliente en miTreeNode) y si cambio las partes
duplicadas en Cliente tengo q cambiar la clase miTreeNode.

Muchas gracias por la ayuda Tristan
Respuesta Responder a este mensaje
#7 olopeich
14/04/2005 - 15:33 | Informe spam
Siguiendo mi diseño, no necesitas una propiedad TreeNode. En principio, el
treenode sería privado al objeto Cliente. Se crearía cuando notifiques al
objeto que tiene que representarse. En ese momento suministrarías un
TreeView, ListView o lo que sea preciso, para que sirva de marco a la
visualización del cliente. El TreeNode, etc... se generará internamente
con la información necesaria y desde la propia clase se asignará como nodo
del TreeView. Espero haberme explicado.

Por el contrario, siguiendo el diseño de George, harías lo contrario. En
ese caso, crearías una clase heredada de TreeNode, otra de ListViewItem,
etc... que tenga una propiedad de tipo Cliente, de ella sacaría los datos
la clase para su representación.



entiendo ambas formas, pero bajo mi humilde opinion casi prefiero la de
george, aunque la tuya suena a mas profesional... no se...

El problema es q claro, tengo varios objetos (cliente, presupuesto, factura
etc...) y claro, heredar de treenode por ejemplo y crear una propiedad para
cad tipo de objeto... eso en principio no me supone mucho marron porque el
programa es uno concreto y no creo q se modifique en un futuro, pero si
tengo q añadir objjetos y representaciones en un futuro...

Yo creo que con más razón ahora debes seguir el diseño que te ha propuesto
George. Si tienes objetos derivados de TreeNode, que tienen una propiedad
Cliente, es inmediato tanto obtener los nodos en los que has hecho click,
como obtener de ellos el Cliente asociado. Además, en efecto, quedará todo
más limpio.



pues decididio. Ademas lo que tendria q cambiar es muy poco.

Lo de que no ves claro para que es un interface. Bueno, yo diría que es lo
más útil de la OOP. Sin duda más que la herencia. La utilidad fundamental
de la herencia no es la herencia de código, aunque sea útil, sino el
polimorfismo. Es decir poder utilizar varias clases de forma genérica sin
importar como cada una implementa el método concreto. En este sentido son
tan importantes las interfaces, puesto que de cara al polimorfismo
permiten lo mismo que la herencia.



hasta aqui bien.

En el viejo vb, y todavía en vb.net, muchos hacen polimorfismo sin
utilizar interfaces, mediante late binding. Llamando a miembros que el
compilador desconoce, esperando que el enlace se haga en tiempo de
ejecución. Esta es una pésima forma de trabajo, muy poco eficiente, y
sobre todo insegura, puesto que el compilador no detecta errores. Las
interfaces son lo adecuado para lograr polimorfismo múltiple.



es como lo hago yo, asignar a una variable de tipo padre un objeto de un
tipo derivado. El compilador decide el metodo al que se llama segun el tipo
del objeto y no del contenedor. La verdad es q sigo sin ver la utilizad de
las interfaces, a no ser la de decirle al compilador los metodos que
implementa el objeto y supongo q de esta forma resolver en early binding
cosas q con la herencia normal se resolverian en late... pero a fin de
cuentas es mas de lo mismo no? quicir, mejora la ejecucion pero no la
funcionalidad y no resuelve el problema de duplicar codigo (si tengo 4
objetos q implementan una interface determinada, aun siendo la misma
interface y mismo pedazo de codigo tendre q duplicarlo en todos)

Pufff y tu mensaje es muy largo, poco a poco... :-)



es q se me ha juntado el hambre con las ganas de comer :)))
Respuesta Responder a este mensaje
#8 olopeich
14/04/2005 - 15:38 | Informe spam
A ver... yo lo que haria seria guardar una referencia al objeto
cliente (o el objeto cliente entero todo depende del diseño en cada
objeto TreeNode).
Lo que pasa es que el objeto TreeNode en si esta bastante limitado
segun viene... pero es lo bueno de la OOP, que se puede ir haciendo
mas concreto segun lo necesitemos.
Yo haria una clase que heredara de TreeNode, pero que contuviese un
objeto cliente (o una referencia a el).

Por ejemplo:



es justo lo que me han sugerido y tenia pensado hacer. Mil gracias por
expresarlo de forma grafica :)

Puede que el objeto Cliente ocupe bastante memoria y no es plan de
rellenar el TreeView con cada objeto cliente cargado en memoria.



nah, en eso no hay problema. El objeto cliente es bastante ligero.

Como ves, la herencia multiple es absolutamente innecesaria. Lo que



si, de esta forma si q es innecesaria. No se me habia ocurrido esta forma de
implementarlo.

Espero que todo esto te ayude!!



me ayuda de largo ademas :)

muchas gracias por tus explicaciones roberto. Tendre q modificar bastantes
cosas pero mejor asi, q quede un poco decente a la vista :)
Respuesta Responder a este mensaje
#9 Tristan
14/04/2005 - 18:49 | Informe spam
es como lo hago yo, asignar a una variable de tipo padre un objeto de un
tipo derivado. El compilador decide el metodo al que se llama segun el
tipo del objeto y no del contenedor. La verdad es q sigo sin ver la
utilizad de las interfaces, a no ser la de decirle al compilador los
metodos que implementa el objeto y supongo q de esta forma resolver en
early binding cosas q con la herencia normal se resolverian en late...
pero a fin de cuentas es mas de lo mismo no? quicir, mejora la ejecucion
pero no la funcionalidad y no resuelve el problema de duplicar codigo (si
tengo 4 objetos q implementan una interface determinada, aun siendo la
misma interface y mismo pedazo de codigo tendre q duplicarlo en todos)



No entiendo lo que dices. ¿Con la herencia normal se resuelven en late?. No,
en absoluto, tanto con la herencia normal como con las interface se
resuelven en early (bueno no exactamente en early pero ese es otro tema).
Como te decía de cara al polimorfismo, herencia e interface hacen
EXACTAMENTE lo mismo. De hecho si se admitiese herencia múltiple las
interfaces no tendrían ninguna utilidad y no existirían. Si te has fijado en
el rollo que te he contado, la razón de que "for each" se base en una
interface es que de esta forma no obliga a seguir ninguna jerarquía de
clases. Cualquier clase puede ser recorrida como colección con tal de
implementar IEnumerable. Lo mismo pasa con ISerializable o tantas otras
interface. Si se utilizase herencia y no interfaces, Enumerable y
Serializable deberían ir ligadas puesto que mediante herencia solo pueden
seguir una jerarquía lineal. No podrías añadir soporte de serialización a
una clase que herede de otra, ya programada, si la linea jerarquica no
incluye Serializable, por ejemplo.

Solo te puedo asegurar que las interfaces se utilizan enormemente, todo .net
hace uso continuo de ellas. Observa la jerarquía de clases y mira el gran
número de interfaces que se utilizan. Intenta imaginar eso mismo sin
interfaces con herencia simple, y verás que es imposible. Se entrecruzarían
las lineas jerarquicas una y otra vez y con herencia simple es imposible
producir un cruce en una línea jerarquica. No se si me explico.

Lo que te resultará más extraño es por que entonces no se admite herencia
múltiple. Bueno, la mayor parte de pensadores sobre el tema consideran,
desde siempre, que la herencia múltiple es una fuente de problemas y
prácticamente nunca una ventaja. Por un lado está el problema de la
ambigüedad. El mismo método heredado de dos vias (ToString por ej.) podría
tener código diferente por cada una de las líneas de herencia. Por otro lado
y relacionado, la jerarquía queda entrecruzada y cuando crece es muy difícil
de seguir. La solución de .net y de la mayor parte de lenguajes OOP es
impedir la herencia múltiple. Pero puesto que de cara al polimorfismo la
herencia múltiple es muy útil, .net al igual que Java, impide la herencia
múltiple de código pero no la herencia múltiple de la declaración en si, es
decir de la interface del objeto.

Espero haberme explicado.

Juan Carlos Badiola
MVP - C#
Respuesta Responder a este mensaje
#10 olopeich
15/04/2005 - 13:21 | Informe spam
No entiendo lo que dices. ¿Con la herencia normal se resuelven en late?. No,



depende. Si asignas a una variable de tipo A un objeto de tipo B, siendo
B una clase derivada de A, el compilador no sabe en tiempo de
compilacion el tipo de objeto que tiene la variable y por tanto a que
metodos llamar (los de A o los de B). Es por eso q se resuelven en
ejecucion (en late binding).

Vamos, esto es de libro pero lo mismo estoy metiendo el zanco pero bien.

en absoluto, tanto con la herencia normal como con las interface se
resuelven en early (bueno no exactamente en early pero ese es otro tema).



quiza ese esa el tema. Yo es q como te decia no estoy muy puesto en este
tema, y dire q me parece apasionante.. :)

interface es que de esta forma no obliga a seguir ninguna jerarquía de
clases. Cualquier clase puede ser recorrida como colección con tal de
implementar IEnumerable. Lo mismo pasa con ISerializable o tantas otras



vamos a ver, quiza aqui tenga yo el agujeron mental. Yo tengo una clase
q implementa ienumerable. Automaticamente mi clase hereda el codigo q
permitira a mi clase ser utilizada en un for each o por contra tengo q
implementar ese codigo por mi mismo.

seguir una jerarquía lineal. No podrías añadir soporte de serialización a
una clase que herede de otra, ya programada, si la linea jerarquica no
incluye Serializable, por ejemplo.



esto lo entiendo.

Solo te puedo asegurar que las interfaces se utilizan enormemente, todo .net
hace uso continuo de ellas. Observa la jerarquía de clases y mira el gran
número de interfaces que se utilizan. Intenta imaginar eso mismo sin
interfaces con herencia simple, y verás que es imposible. Se entrecruzarían



claro, es q con herencia simple y solo con ella la cosa esta
extremadamente limitada.

las lineas jerarquicas una y otra vez y con herencia simple es imposible
producir un cruce en una línea jerarquica. No se si me explico.



en este punto perfectamente.

múltiple. Bueno, la mayor parte de pensadores sobre el tema consideran,
desde siempre, que la herencia múltiple es una fuente de problemas y
prácticamente nunca una ventaja. Por un lado está el problema de la



esto tambien lo sabia pero como nunca he utilizado un lenguaje q me
permita herencia multiple no veo lso problemas q puede acarrear. Los
problemas los puedo imaginar pero ya sabes, no haberlso padecido hace q
parezcan menores.

saludos
Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida