Ir al contenido


Foto

¿Un TCollectionItem puede ser objeto de otra clase?


  • Por favor identifícate para responder
16 respuestas en este tema

#1 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 29 febrero 2012 - 04:44

Buenas,

A ver si me se explicar jejeje

Por un lado tengo una clase que "tiene" una TCollection

TGMInfoWindow -> TInfoWindows (TCollection) -> TInfoWindow (TCollectionItem)

Y por otro lado tengo otra clase (TMarker) que necesita tener un objeto TInfoWindow. Se que es posible poner a la clase TMarker un objeto de tipo TInfoWindow, pero la duda es,  ¿Es correcto hacer esto? Si no lo fuera... ¿Cómo lo haríais?

Gracias

Nos leemos
  • 0

#2 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 01 marzo 2012 - 01:09

Después de dormir se ven las cosas un poco más claras jejeje

Dado que no me gusta la idea de usar en una clase que no es una TCollection, un TCollectionItem, he pensado cómo poder hacerlo (a no ser que alguien con más conocimientos que yo me diga que sí es buena idea)

La idea sería hacer una clase que derive de TPersistent con lo que quiero que haga mi TInfoWindow , por ejemplo (y reduciendo la clase a la mínima expresión)



delphi
  1.   TBaseInfoWindow = class(TPersistent)
  2.   private
  3.     FContent: TStrings;
  4.   published
  5.     property Content: TStrings read FContent write FContent;
  6.   end;



Con esto, ya podría crear una propiedad en la clase TMarker sin problemas.

Luego, y dado que Delphi no permite la herencia múltiple, en TInfoWindow (TCollectionItem) la idea sería hacer lo mismo que en TMarker, pero en este caso creo que quedaría "feo" en el Inspector de Objetos (¿¿¿1 sola propiedad que sea un objeto??? uf uf uf). Para mirar de salvar este "mal aspecto" y dado que TBaseInfoWindow no va a tener mucha cosa, puedo poner una propiedad/variable privada de tipo TBaseInfoWindow y mirar de repetir las propiedades de éste en la parte published y programar el read y write para que acceda a las propiedades del objeto, algo así



delphi
  1.   TInfoWindow = class(TCollectionItem)
  2.   private
  3.     FBaseInfoWindow: TBaseInfoWindow; // objeto privado de la clase que quiero heredar
  4.     function GetContent: TStrings;
  5.     procedure SetContent(const Value: TStrings);
  6.   published
  7.     property Content: TStrings read GetContent write SetContent; // propiedad de la clase que quiero heredar
  8.   end;
  9.  
  10. .......
  11.  
  12. function TInfoWindow.GetContent: TStrings;
  13. begin
  14.   Result := FBaseInfoWindow.Content;
  15. end;
  16.  
  17. procedure TInfoWindow.SetContent(const Value: TStrings);
  18. begin
  19.   FBaseInfoWindow.Content.Assign(Value);
  20. end;



¿Qué os parece?

Gracias

Nos leemos
  • 0

#3 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 01 marzo 2012 - 07:46

Hola Cadetill, no termino de comprender lo que quieres lograr. Se que tiene que ver, en parte, con otros hilos en donde hemos debatido y analizado el uso de las clases TColletion y TCollectionItem y tus clases TMaker pero ahorita no le logro captar el tema y ver como están hechas las relaciones entre las clases.
Si me puedes dar más pistas tal vez pueda apreciar cual es la mejor salida al tema.

Saludos,
  • 0

#4 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 01 marzo 2012 - 09:56

Hola Delphius

A ver, te comento.

Como sabrás, estoy con el tema de los componentes para encapsular la API de Google Maps. Pues bien, de momento tengo definida esta gerarquía de clases (unas imágenes valen más que 1000 palabras dicen)

Imagen Enviada

Bien, yo quiero que mis TMarker tengan un objeto de tipo TInfoWindow (que es un TCollectionItem). Como dije en el primer mensaje, por poder, Delphi deja hacerlo, y preguntaba que, aunque Delphi deje hacerlo, si era correcto. Si no lo fuera, en el segundo mensaje propongo una solución, que sería hacer lo siguiente

Imagen Enviada

Es decir, crear una clase que haga lo que tendría que hacer el original TInfoWindow (TBaseInfoWindow) y ponerla como propiedad publicada tanto en TMarker como en el TInfoWindow.

Si pensamos en el Inspector de Objetos y cómo se vería esta propiedad en él (al ser un objeto saldía el nombre de la propiedad con la opción de desplegar para ver sus propiedades), veo que en el TMarker puede quedar bien (hay varias propiedades y ésta sería una más). Pero en el TInfoWindow puede quedar como un pegote (sólo tendría esta propiedad que necesitaría ser "desplegada" para acceder a sus características). De ahí la "paranoia" mia del segundo post.

Espero haberme explicado algo mejor

Gracias

Nos leemos
  • 0

#5 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 01 marzo 2012 - 12:44

Hola Cadetill,
Me ha confundido un poco el diagrama, no lograba entenderlo hasta que le noté el error: están mal formada las relaciones, las puntas de flecha van al revés.  ;)

Creo entender tu duda: resulta ser que tanto TMaker y TInfoWindow (siendo que ambos heredan  de TColletionItem) necesitarían de una propiedad en común denominada Content que les ofrecería a ambas clases algo que les he de utilidad. Y estás en la duda de si es conveniente disponer de una clase base de la cual ambos hereden e implemente los mecanismos set y get seguros y adecuados a cada uno ó si directamente conviene mantener esta propiedad en la clase TInfoWindow y directamente vincular a TMaker con TInfoWindow mediante un atributo para que éste de forma indirecta haga uso de Content.

Viendo así las cosas me inclino por la opción de disponer de una clase base con dicha propiedad y que TMaker y TInfoWindow la publiquen, y si es necesario que implementen y/o sobreescriban los métodos set y get.
Si te fijas, la VCL está llena de clases abstractas con muchas propiedades y métodos protegidos que luego sus descendientes le cambian la visibilidad a público y/o publicado. Las clases TCustomXXX son un buen ejemplo.

Ahora bien, esa clase base yo la haría heredar de TColletionItem y pondría en ella lo necesario y común que hiciera a un TColletionItem especializado tanto para el contexto de la dupla {TMakers, TMaker} como a la {TInfoWindows, TInfoWindow}... Quizá no sea apropiadado el nombre TBaseInfoWindow, quizá un TCustomItemContext  ;) El nombre da a entender que se trata de un TColletionItem cualquiera (abstracto) que posee la propiedad Context... cosas de semántica  :)

Es decir algo como:



delphi
  1. +--------+ +-------------+
  2. | TMaker | | TInfoWindow |
  3. +--------+ +-------------+
  4.     \              /
  5.       \            /
  6.       V          V
  7.     +--------------------+
  8.     | TCustomItemContext |
  9.     +--------------------+
  10.               |
  11.               |
  12.               V
  13.     +----------------+
  14.     | TColletionItem |
  15.     +----------------+



El sentido de la fecha significa "hereda de".
Ahora bien, no sería de extrañarse, ahora viendo este TCustom si nos aparece la duda de si por casualidad no apareciera una clase TCustomContext que heredara de TColletion y por tanto ahora TMakers y TInfoWindows podrían heredar de ésta.

Permíteme aclararte que es legal hacer que una colección, (o un ítem de una colección... incluso; aunque para este caso yo me lo preguntaría varias veces si es lo más apropiado) tenga como propiedad (y por tanto un vínculo o relación) hacia otra colección; más no así hacia un ítem de esa segunda colección. ¿Porqué? Porque se supone que el acceso al ítem es por medio de su "administrador" o "dueño".

Si en verdad el contexto {TMakers, TMaker} necesita colaborar con el de {TInfoWindows, TInfoWindow} por algo más hallá de una simple propiedad que uno tuviera y el otro no entonces yo propondría que sea el TMaker quien tenga visibilidad de atributo hacia TInfoWindows de modo que si un ítem de TMakers (TMaker) debe acceder a algo de TInfoWindow/TInfoWindows lo haga por medio de su dueño. De este modo TMakers delega parte de su trabajo a TInfoWindows. Espero que se me entienda.

Las necesidades y otras consideraciones de diseño a tener en cuenta dirán que es lo más apropiado. Pero así, como me lo ilustras me inclino por el TCustomItemContext  ;)  :)

Saludos,
  • 0

#6 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 01 marzo 2012 - 04:43

Ante todo gracias por responder

Respecto a las flechas del diagrama, pues tienes razón, es lo que tiene el hacerlo en 5min, que no te ficjas en las cosas jejejeje Ya lo he corregido, creo que ahora está bien :)

Respecto a la duda, creo que no me has entendido o yo no te he entendido a ti, jejeje

No es que TMaker y TInfoWindow necesiten una propiedad en común (que son varias, eso era un mero ejemplo), sino que esas propiedades son la clase TInfoWindow



delphi
  1.   TInfoWindow = class(TCollectionItem)
  2.   private
  3.     .....
  4.   public
  5.     .....
  6.   published
  7.     property Content: TStrings read FContent write FContent;
  8.     property DisableAutoPan: Boolean read FDisableAutoPan write FDisableAutoPan;
  9.     property MaxWidth: Integer read FMaxWidth write FMaxWidth;  // 0 = no MaxWidth
  10.     property PixelOffset: TSize read FPixelOffset write FPixelOffset; // (0,0) = no pixelOffset
  11.   end;



La clase TInfoWindow representa esos balloon que aparecen con información al hacer clic encima de un marcador (por ejemplo) en los mapas de Google. Estas ventanas con información pueden estar ligadas al mapa directamente (de ahí que TGMInfoWindow herede de TGMLinkedComponent => componente de acceso al mapa) o bien a un objeto del mapa (como el TMarker).

Dado que un TMarker puede contener una ventana de información (TInfoWindow), pero no puede contener (o no debería contener) un objeto de tipo TCollectionItem, necesito alguna clase que me represente esa ventana pero que herede de TPersistent. Por eso pensé en la creación de la clase TBaseInfoWindow, que realmente es un TInfoWindow, y que puede ser una propiedad de los objetos que van al mapa (como TMarker).

Ahora bien, si creo esa clase, ¿cómo quedaría TInfoWindow? Pues algo así



delphi
  1.   TInfoWindow = class(TCollectionItem)
  2.   private
  3.     .....
  4.   public
  5.     .....
  6.   published
  7.     property BaseInfoWindow: TBaseInfoWindowread FBaseInfoWindow write FBaseInfoWindow;
  8.   end;



Claro, eso queda fatal en el Inspector de Objetos, por eso había pensado lo explicado en el segundo mensaje.

A ver si ahora nos entendemos jejejeje

Gracias de nuevo

Nos leemos
  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 01 marzo 2012 - 05:05

Xavier,
Evidentemente entendí cualquier otra cosa  :(  :

Ummm, estoy reordenando las cosas en mi cabeza y todavía no logro coordinar algo que me cuadre.
Algo me dice que tal vez, y sólo tal vez, las cosas no pasen ni por lo uno ni lo otro; sino de un poco de rediseño y alterará en parte tu estructura. Por el momento me inclino hacia un poco de clase de asociación y a una aplicación de agregación compartida; aunque sin encontrar una forma de unir los cabos.
Necesito de mucho combustible en mi estómago y de un reseteo para lograr unir conceptos y tener algo más fresco. No quisiera aventarme otra respuesta que no te conduzca a la nada.

Si no tienes prisa...

Saludos,
  • 0

#8 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 01 marzo 2012 - 05:17

Si no es mucha molestia, ¿podrías comentar de manera breve pero puntual que representa, y que objetivo y/o función cumple cada una de las clases que muestras en el diagrama (excepto de las que ya comentaste por supuesto)?

Quizá te parezca que no viene al caso pero me ayudará a comprender tu modelo y en cómo están distribuidas las funciones y responsabilidades de cada clase.

Si, el diagrama ahora está bien. No hacía falta corregirlo; aunque se agradece. Mi cabeza ni bien comprendió el sentido hacía la corrección.

Saludos,
  • 0

#9 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 02 marzo 2012 - 01:41

Claro que no es problema amigo Delphius, es más, este tipo de respuestas me ayudarán a posteriori documentar los componentes :-)

TGMBase: clase base de todos los componentes de acceso a la API de Google Maps. Contiene las propiedades genéricas a todos los componentes que son 3, el "acerca de", el idioma con el que se quiere mostrar las excepciones lanzadas por el componente en caso de error y una propiedad string donde pongo la url a la API de Google Maps de la parte que encapsula el componente que herede de TGMBase para una mayor y fácil referencia.

TGMMap: componente que diseña el mapa plano, sin objetos, sólo con lo necesario para visualizar una zona y desplazarte por la misma (zoom, scroll, ......). También es el que gestiona la comunicación con el mapa a nivel de eventos y/o cambio de cualquier tipo de propiedad/objeto del mapa. A su vez, mantiene un TList con todo objeto que se linca a él y que representa algún objeto en el mapa (marcadores, ventanas de información, lineas, polilíneas, rectángulos,......)

TGMLinkedComponent: clase base para cualquier componente que se quiera lincar a TGMMap. Controla el lincado y deslincado de un mapa, el borrado del componente mapa lincado o el propio borrado y tiene algunos métodos para comunicarse con TGMMap para el envío/recepción de información hacia/del mapa (recordemos que sólo TGMMap se comunica con el mapa).

TGMMarker: componente que mantiene una relación de marcadores (clase TMarker) mediante una TCollection (TMarkers)

TGMInfoWindow: componente que mantiene una relación de ventanas de información o balloons (clase TInfoWindow) mediante una TCollection (TInfoWindows)

Las demás ya son de Delphi jejejeje

Gracias

Nos leemos

  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 02 marzo 2012 - 11:51

Te agradezco Xavier que me hayas pasado dicha info. Dedicaré un tiempo para ir analizando y repasando incluso lo que se había hablado antes sobre las clases Maker.
Creo que analizando las cosas desde una perspectiva más "global" me será más fácil entender el problema, y el cómo has estado llevando tu diseño.
Espero que no te moleste si me demoro en comentarte algo.

Saludos,
  • 0

#11 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 02 marzo 2012 - 01:34

Yo no tengo prisa amigo, así que tómate el tiempo que necesites :)

Nos leemos
  • 0

#12 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 08 marzo 2012 - 04:50

Hola,
Disculpa Xavier pero no he podido darme tiempo para ver esto. Estoy muy apretado de tiempo... con mucha suerte el domingo pueda tener más tiempo libre y poder estudiar esto con detalle. De lo que estuve analizando y pensando se podría hacer unos cuantos cambios a esa jerarquía de clases y se podría aprovechar de un poco de polimorfismo y algunos conceptos prestados de patrones que harían más liviano tu diseño y quizá estabilizar algunos puntitos que quizá estén medios flojos.
Se que no es demasiado bueno retocar una jerarquía de clases pero a como lo entiendo, me parece mejor.

Espero que no te moleste que te haya dejado descolgado; tenme paciencia.
Si avanzaste en algo, o estuviste aplicando algunos cambios no estaría mal que nos los comentes.

Saludos,
  • 0

#13 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 09 marzo 2012 - 02:28

Hola amigo Delphius

Tranquilo, sin prisas :-)

A nivel de los componentes, realmente sí he retocado algo la gerarquía de clases, no mucho, pero algo. Te adjunto un archivo con los diagramas actuales (formato JPG). También verás un archivo .uml que es el diseño en sí (se abre con un programa opensource (staruml) la web del cual encontrarás en el readme.txt) por si quieres ver/retocar el diseño completo

A nivel de gerarquía, decir que las colecciones que tendrán las clases que se podrán unir al mapa (TMarkers, TInfoWindows, TPolylines, TPolygons,....) no heredan directamente de TCollection, sino de una clase intermedia. Lo mismo pasará con los TCollectionItems. Esto lo he hecho para pasar gran parte del trabajo repetitivo a estas nuevas clases (TLinkedComponents y TLinkedComponent).

Es en la nueva clase TLinkedComponent (TCollectionItem) donde he puesto una propiedad protegida de tipo TBaseInfoWindow. La clase TBaseInfoWindows representa una ventana de información (un balloon). Las clases que deriven de TLinkedComponent lo único que tendrán que hacer es publicar esta propiedad.

Si quieres también podría colgar los fuentes, los componentes TGMMap y TGMMarker son funcionales y, quizás viendo el código, se entienda algo mejor.

Gracias de nuevo

Nos leemos

  • 0

#14 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 09 marzo 2012 - 12:02

Hola,
Tomo nota de tus cambios y ya he descargado el archivo adjunto. Lo veré en cuanto pueda.

A StarUML ya lo conozco... yo también lo utilizo.
Si los fuentes requieren de alguna biblioteca de terceros no serviría de mucho que lo descargue; aunque también podría ayudar a entenderle la mano; te comento que utilizo D6.
Si tu crees conveniente y apropiado colocar los fuentes, por mi está bien; ahora si no están liberados todavía (o no lo has considerado todavía, y/o si son pagos) creería que lo más apropiado sería que no los envíes.

Saludos,
  • 0

#15 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 10 marzo 2012 - 05:21

Buenas,

Los componentes van a ser opensource, bajo licencia GPL o MPL, eso aun no está decidido, así que no es problema en colgar los fuentes. No uso ni componentes ni librerías de terceros (al menos por ahora, más adelante quizás use una librería para la lectura de archivos JSON)

Imagino que te compilarán sin muchos problemas en D6. Yo no lo tengo aquí instalado, pero sí en el trabajo. El lunes podría probar si compila en esa versión. De momento están compilados en D2010. Mi idea era compilarlos en D6, D7, D2007, D2010 y DXE2, que son los que tengo en el trabajo instalados, pero a la que estuviera la cosa un poco más madura.

Lo que sí no garantizo es que te salte algún error no controlado, que aun no he podido hacerle un fuerte juego de pruebas xD

Archivos adjuntos


  • 0

#16 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 23 marzo 2012 - 12:21

Hola,
Mil disculpas Xavier por tenerte abandonado. No pensé que me tuviera consumiendo tanto tiempo mi proyecto  :( y algunos pequeños dolores de cabeza y pérdidas de neuronas  :D

Sinceramente no se en que momento pueda sentarme a hecharle ojo. Si bien tu me dices que no tienes prisa, siento que yo te quedo en falta  :(
Si lograse avanzar y llegar al hito programado más cercano en mi proyecto antes de tiempo si podría darme el relax y concentrarme en esto. El poco relax que me he estado permitiendo son unos minutos al día de facebook, como para "apagar" y desenchufarme, tanto de proyecto como de Delphi.

Ojalá estés pudiendo avanzar, y por lo que estuve viendo en los foros estos minutos, ya has estado liberando tu biblioteca. Considero a estas alturas, que si ya te ha estado funcionando bien según tu diseño es mejor no tocarlo; y en todo caso dejar estos tipos de cambios como para una versión posterior.

Mis más sinceras disculpas por no poder asistirte en tiempo y forma. ¡A ver si alguien más se anima a meter mano al hilo!

Saludos,
  • 0

#17 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 25 marzo 2012 - 01:32

jejeje, tu tranquilo, no desesperes, ya te lo mirarás con calma el día que tengas tiempo :-)

Y si los cambios son buenos, da igual que se tenga que hacer un cambio de estructura en la jerarquía de clases, por eso no hay problema ;-)

Nos leemos

  • 0




IP.Board spam blocked by CleanTalk.