tag:blogger.com,1999:blog-1292532279691646783.post6799023736067785467..comments2023-10-19T10:10:40.775-03:00Comments on Modelos de Software con Objetos: ¿Cómo asegurar la evolución de un sistema?" - Parte II - VisitorHernan Wilkinsonhttp://www.blogger.com/profile/15637852043224382103noreply@blogger.comBlogger2125tag:blogger.com,1999:blog-1292532279691646783.post-1378673711592457142007-10-05T12:55:00.000-03:002007-10-05T12:55:00.000-03:00Que haces Diego!, gracias por el comentario... te ...Que haces Diego!, gracias por el comentario... te respondo lo que pienso acá:<BR/>---- Comentario de Diego ---<BR/>Lo que no me queda claro es cuantas veces el nombre "XXX" del #visitXXX no depende de la clase en si, supongamos esta jerarquia:<BR/>---- Fin deComentario de Diego ---<BR/><BR/>Para mi dependen completamente del nombre de la clase. O sea, este patrón tiene por intención recorrer objetos pertenecientes a una jerarquía de clases y tratarlos de manera distinta según que tipo de objetos son (o lo que significa, de que clase son instancia)<BR/><BR/>---- Comentario de Diego ---<BR/>DocumentElementBehavior (define accept:)<BR/>Paragraph>>accept: aVisitor<BR/>aVisitor visitParagraph: self<BR/><BR/>Ahora agrego una sub-clase de DocumentElementBehavior, que es un nuevo tipo de parrafo: DocumentElementBehavior subclass: <BR/>#MySuperSpecificParagraph MySuperSpecificParagraph>>accept: aVisitor<BR/>aVisitor visitParagraph: self<BR/>---- Fin de Comentario de Diego ---<BR/>Desde mi punto de vista está mal. El mensaje visit a enviar debería ser visitMySuperSpecificParagraph, no visitParagraph porque ese mensaje se usa para los objetos instancia de la otra clase... de lo contrario no hay manera de distinguir el tipo de un objeto, objetivo principal de este patrón.<BR/><BR/>---- Comentario de Diego ---<BR/>De esta forma mi nueva sub-clase es compatible con los visitors existentes de la jerarquia de DocumentElementBehavior.<BR/>---- Fin Comentario de Diego ---<BR/><BR/>En realidad lo que hay que hacer es modificar los visitors para que tengan en cuenta el nuevo mensaje. El no hacerlo es patear un problema para más adelante.<BR/>---- Comentario de Diego ---<BR/>Pero que pasa si en algún otro contexto quiero diferenciar el comportamiento del visitor para un MySuperSpecificParagraph, bueno la opción que tengo es agregar un nuevo visitXXX:<BR/><BR/>MySuperSpecificParagraph>>accept: aVisitor<BR/>aVisitor visitMySuperSpecificParagraph: self<BR/><BR/>Y tocar todos los visitors existentes, para que en #visitMySuperSpecificParagraph: o bien no hagan nada o bien hagan self visitParagraph: aMySuperSpecificParagraph (suponiendo que MySuperSpecificParagraph es polimorfico a un Paragraph y que los quiero tratar igual en este contexto... lo cual no es un decisión menor).<BR/>------ fin de comentario ----<BR/>Eso es lo que haría siempre. O sea, agregar una clase a la jerarquía implica enviar un nuevo mensaje visitXXX y por lo tanto modificar todos los visitors que recorren esa jerarquía<BR/><BR/>---- Comentario de Diego ---<BR/>El problema es que cuando la jerarquia de DocumentElementBehavior tiende a ser grande hay una proliferación enorme de visitXXX que hay que mantener (jejeje te imaginaras por que elegi el nombre MCPDocumentElementBehavior.. ejem quiero decir DocumentElementBehavior ;) ).<BR/>---- Fin de Comentario de Diego ---<BR/>Si, me imagino jaja.<BR/>Pero bue, no queda otra, es una característica de este patrón. El problema no es que haya mucho mensajes sino no olvidarse de tener en cuenta ninguno... y para eso es la herramienta que hice. Si hay que analizar cada caso de la jerarquía no hay otra, no se puede evitar hacerlo.<BR/><BR/>---- Comentario de Diego ---<BR/>Me parece que otra forma de resolver ese double dispatch es el tipico "canHandle" (hey! debería haber un patron con ese nombre):<BR/><BR/>Paragraph>>accept: aVisitor<BR/>aVisitor visit: self<BR/><BR/>MyVisitor>>visit: aDocumentElement<BR/>(self handlerFor: aDocumentElement) value: aDocumentElement<BR/><BR/>MyVisitor>>handlerFor: aDocumentElement<BR/>^handlers detect: [:each | each canHandle: aDocumentElement ] ifNone: [self nullHandler]<BR/><BR/>Eso reduciria la proliferación de #visitXXX, y evitaria posibles DNUs... <BR/>---- Fin Comentario de Diego ---<BR/>No veo la ventaja... o sea, como decidir el handler hay que mantenerlo si se agregan nuevas clases también y hay que asegurarse de hacerlo. Además también hay que tener en cuenta los nuevos casos, no se puede safar de esto... hmm, no se, no veo que simplifique el problema...<BR/><BR/>Un abrazo,<BR/>HernánHernan Wilkinsonhttps://www.blogger.com/profile/15637852043224382103noreply@blogger.comtag:blogger.com,1999:blog-1292532279691646783.post-81834491156053288032007-10-04T00:32:00.000-03:002007-10-04T00:32:00.000-03:00A mi me siguen quedando dudas acerca de que tan bu...A mi me siguen quedando dudas acerca de que tan bueno es el patron Visitor.<BR/><BR/>Lo copado de este pattern es que el objeto que recibe el #accept: es quien decide como se debe recorrer su propia estructura.<BR/><BR/>La parte que no me copa es justo la que trae los problemas que comentas en el post, la del double dispatch con el #visitXXX :(<BR/>Lo que no me queda claro es cuantas veces el nombre "XXX" del #visitXXX no depende de la clase en si, supongamos esta jerarquia:<BR/><I><BR/>DocumentElementBehavior (define accept:)<BR/> Paragraph>>accept: aVisitor<BR/> aVisitor visitParagraph: self<BR/></I><BR/><BR/>Ahora agrego una sub-clase de DocumentElementBehavior, que es un nuevo tipo de parrafo:<BR/><I><BR/>DocumentElementBehavior subclass: #MySuperSpecificParagraph<BR/> MySuperSpecificParagraph>>accept: aVisitor<BR/> aVisitor visitParagraph: self<BR/></I><BR/>De esta forma mi nueva sub-clase es compatible con los visitors existentes de la jerarquia de DocumentElementBehavior.<BR/>Pero que pasa si en algún otro contexto quiero diferenciar el comportamiento del visitor para un MySuperSpecificParagraph, bueno la opción que tengo es agregar un nuevo visitXXX:<BR/><BR/><I> MySuperSpecificParagraph>>accept: aVisitor<BR/> aVisitor visitMySuperSpecificParagraph: self<BR/></I><BR/>Y tocar todos los visitors existentes, para que en #visitMySuperSpecificParagraph: o bien no hagan nada o bien hagan self visitParagraph: aMySuperSpecificParagraph (suponiendo que MySuperSpecificParagraph es polimorfico a un Paragraph y que los quiero tratar igual en este contexto... lo cual no es un decisión menor).<BR/><BR/>El problema es que cuando la jerarquia de DocumentElementBehavior tiende a ser grande hay una proliferación enorme de visitXXX que hay que mantener (jejeje te imaginaras por que elegi el nombre MCPDocumentElementBehavior.. ejem quiero decir DocumentElementBehavior ;) ).<BR/><BR/>Me parece que otra forma de resolver ese double dispatch es el tipico "canHandle" (hey! debería haber un patron con ese nombre):<BR/><I><BR/>Paragraph>>accept: aVisitor<BR/> aVisitor visit: self<BR/><BR/>MyVisitor>>visit: aDocumentElement<BR/> (self handlerFor: aDocumentElement) value: aDocumentElement <BR/><BR/>MyVisitor>>handlerFor: aDocumentElement<BR/> ^handlers detect: [:each | each canHandle: aDocumentElement ] ifNone: [self nullHandler]<BR/></I><BR/>Eso reduciria la proliferación de #visitXXX, y evitaria posibles DNUs... al costo que ahora detectar la ausencia de un "handler" para un DocumentElement especifico es más dificil, ouch!Diego Fernándezhttps://www.blogger.com/profile/11282484801526539091noreply@blogger.com