<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2915850027029705420</id><updated>2012-01-27T15:39:56.222-08:00</updated><category term='Proyectos'/><category term='Patrones de Diseño'/><category term='Análisis y Diseño Orientado a Objetos'/><title type='text'>Jahepi´s Blog</title><subtitle type='html'>Programación Orientada a Objetos, Actionscript 3.0 y tratando de construir la matrix.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-5075758244338617914</id><published>2008-07-03T14:41:00.000-07:00</published><updated>2008-12-10T21:28:04.437-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Proyectos'/><title type='text'>Documentación Mp3Player - ActionScript 2.0</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Hola !&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Les traigo una api que hice hace un tiempo pero se me había pasado compartirlo, es para hacer reproductores mp3 en flash con actionscript 2.0, es muy sencillita de utilizar.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;Documentación:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Paquete:&lt;/span&gt; &lt;span style="color: rgb(51, 51, 255);"&gt;com.jahepi.mp3player&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Clase:&lt;/span&gt; public class Track&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Herencia:&lt;/span&gt; &lt;span style="color: rgb(51, 51, 255);"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Encapsula las propiedades básicas de una pista.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Propiedades Públicas&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;url:String&lt;/span&gt;&lt;br /&gt;Dirección del mp3.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;name:String&lt;/span&gt;&lt;br /&gt;Nombre del mp3.&lt;br /&gt;&lt;br /&gt;------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Paquete:&lt;/span&gt; &lt;span style="color: rgb(51, 51, 255);"&gt;com.jahepi.mp3player&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Clase: &lt;/span&gt;public class Player&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Herencia:&lt;/span&gt; &lt;span style="color: rgb(51, 51, 255);"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La clase Player te permite crear reproductores flash de manera sencilla, el objetivo de esta clase era el no acoplar los elementos gráficos y así tener la libertad de realizar tus propios diseños de reproductores.&lt;br /&gt;&lt;br /&gt;Se emplearon 3 patrones de diseño para la realización, uno de ellos el Singleton, esto quiere decir que solamente se puede obtener una instancia de la clase Player, esto lo hice porque en las aplicaciones se utiliza un solo reproductor por lo general.&lt;br /&gt;&lt;br /&gt;Además con Singleton tenemos un acceso global a nuestra instancia.&lt;br /&gt;&lt;br /&gt;El siguiente fue el Patrón de Estado, para manejar los diferentes estados en el que puede estar un reproductor como cuando esta en pausa, en reproducción, etc., y por último uno que va de la mano con el Patrón de Estado , una Fábrica-Peso Ligero para no estar creando instancias de nuestros estados cada ves que se requieran.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Propiedades Públicas&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 102, 255);"&gt;stream:Bolean&lt;/span&gt;&lt;br /&gt;Valor booleano que indica si la carga del mp3 se hace en modo stream.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;volume:Number&lt;/span&gt;&lt;br /&gt;Número del 0 al 100 que indica el volumen del track en reproducción.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Métodos Públicos&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;[Static] getInstance:Player&lt;/span&gt;&lt;br /&gt;Con este método estático obtenemos la instancia de nuestro Player.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;addTrack(track:Track):Void&lt;/span&gt;&lt;br /&gt;Añade un objeto track a la lista de reproducción.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;removeTrackAt(index:Number):Track&lt;/span&gt;&lt;br /&gt;Remueve un objeto track de la lista de reproducción.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;getTrackAt(index:Number):Track&lt;/span&gt;&lt;br /&gt;Obtenemos un objeto track de la lista de reproducción de acuerdo al índice pasado como parámetro.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;tracksIterator():IIterator&lt;/span&gt;&lt;br /&gt;Devuelve un objeto iterador para recorrer la lista de reproducción.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;playTrackAt(index:Number):Void&lt;/span&gt;&lt;br /&gt;Inicia la reproducción de un track de la lista de reproducción de acuerdo al índice pasado como parámetro.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;playNextTrack():Void&lt;/span&gt;&lt;br /&gt;Inicia la reproducción del siguiente track en la lista de reproducción.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;playPrevTrack():Void&lt;/span&gt;&lt;br /&gt;Inicia la reproducción del anterior track en la lista de reproducción.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;getCurrentTrack():Track&lt;/span&gt;&lt;br /&gt;Obtenemos el track actual de la lista de reproducción.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;stop():Void&lt;/span&gt;&lt;br /&gt;Cancela la reproducción del track actual en la lista.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;play():Void&lt;/span&gt;&lt;br /&gt;Inicia la reproducción del track actual de la lista.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;pause():Void&lt;/span&gt;&lt;br /&gt;Pausa la reproducción del track actual de la lista.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;getSeconds():Number&lt;/span&gt;&lt;br /&gt;Obtenemos el número de segundos de la reproducción del track actual de la lista.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;getTrackLoadPercentage():Number&lt;/span&gt;&lt;br /&gt;Obtenemos el porcentaje de carga del track actual de la lista.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;getTrackPlayingPercentage():Number&lt;/span&gt;&lt;br /&gt;Obtenemos el porcentaje de reproducción del track actual de la lista.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;setTrackPosition(percentage:Number):Void&lt;/span&gt;&lt;br /&gt;Cambiamos la posición de reproducción del track actual, el parámetro percentage debe se un número entre el 0 y 100, como 10.2, 99, 32.45, etc…, si el player esta en modo stream y se pone un porcentaje mayor al cargado, este se ajustará automáticamente.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Eventos&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;TRACKLOADINGPROGRESS&lt;/span&gt;&lt;br /&gt;Evento que se dispara cada ½ segundo cuando empieza la carga del track hasta finalizar.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;TRACKLOADINGSTART&lt;/span&gt;&lt;br /&gt;Evento que se dispara cuando la carga del track inicia.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;TRACKLOADINGCOMPLETE&lt;/span&gt;&lt;br /&gt;Evento que se dispara cuando la carga del track finaliza.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;TRACKCOMPLETE&lt;/span&gt;&lt;br /&gt;Evento que se dispara cuando finaliza la reproducción total del track.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 102, 255);"&gt;TRACKPLAYING&lt;/span&gt;&lt;br /&gt;Evento que se dispara cada ½ segundo cuando el track esta en reproducción hasta finalizar.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;ERROR&lt;/span&gt;&lt;br /&gt;Evento que se dispara al ocurrir un error inesperado.&lt;br /&gt;&lt;br /&gt;------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;Les dejo el archivo junto a un ejemplo para que vean cómo se utiliza, cualquier pregunta no duden en contactarme.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.mediafire.com/download.php?naijmgjnnm5"&gt;ARCHIVO&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ojalá les sea útil.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Un saludote !&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-5075758244338617914?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/5075758244338617914/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=5075758244338617914' title='28 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/5075758244338617914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/5075758244338617914'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2008/07/documentacin-mp3player-actionscript-20.html' title='Documentación Mp3Player - ActionScript 2.0'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>28</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-7638515765372390975</id><published>2008-06-21T15:44:00.000-07:00</published><updated>2008-12-11T09:14:41.328-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Proyectos'/><title type='text'>Librería MaskSquareEffect - ActionScript 2.0</title><content type='html'>&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/span&gt;MaskSquareEffect es una librería que te permite realizar varios efectos de mascara con cuadros en flash, aquí hay un panel para que pruebes los distintos efectos que se pueden generar:&lt;/p&gt;&lt;p&gt;&lt;a href="http://jahepi.net46.net/Panel.html"&gt;Ejemplo&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt; Esta  versión utiliza el motor de animaciones TweenLite, el rendimiento ha mejorado  muchísimo, en comparación al motor que viene por defecto en flash (Tween).&lt;br /&gt;&lt;/p&gt;&lt;p style="font-weight: bold;"&gt;¿ Cómo la  utilizo ?&lt;/p&gt;&lt;p&gt;Bajen  primero el archivo &lt;/p&gt;&lt;a href="http://www.mediafire.com/?zvp4mtwn0mz"&gt;MaskSquareEffect.zip&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Primero  debemos descomprimir el archivo, vamos  a  ver una carpeta “com”, esta la extraemos dentro del proyecto donde vamos a  aplicar los efectos.&lt;/p&gt;&lt;p&gt;La clase  principal es MaskSquareEffect, se encuentra en el paquete  com.jahepi.squareeffect.&lt;/p&gt;&lt;p style="font-weight: bold;"&gt;&lt;span style="font-size:180%;"&gt;DOCUMENTACIÓN  MASKSQUAREEFFECT&lt;/span&gt;&lt;/p&gt;&lt;p style="font-weight: bold; color: rgb(255, 153, 0);"&gt;&lt;span style="font-size:180%;"&gt;CONSTRUCTOR&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;1.- MaskSquareEffect(target:MovieClip,  rows:Number, columns:Number, fadeIn:Boolean)&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Crea un nuevo objeto MaskSquareEffect.&lt;/p&gt;&lt;p&gt;Parámetros:&lt;/p&gt;&lt;p style="color: rgb(0, 153, 0);"&gt;target: El nombre de instancia del movieclip al cual le  queremos dar el efecto.&lt;br /&gt;rows: El número de filas que va a ser dividido el movieclip  para hacer el efecto.&lt;br /&gt;columns: El número de columnas que va a ser dividido el  movieclip para hacer el efecto.&lt;br /&gt;fadeIn: Indica si el efecto aparece o desaparece el  movieclip.&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;var effect:MaskSquareEffect = new MaskSquareEffect(mc, 10, 10, true);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="font-weight: bold; color: rgb(255, 153, 0);"&gt;&lt;span style="font-size:180%;"&gt;MÉTODOS&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;1.- play():void&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Inicia la ejecución de la animación.&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.play();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;2.- isPlaying():Boolean&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Retorna verdadero si la animación esta en ejecución y falso  en caso contrario.&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.isPlaying();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;3.- remove():void&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Remueve la máscara que se creo dinámicamente al hacer el  efecto, solamente se puede remover si la mascara ha sido creada y si la  animación no esta en ejecución.&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.remove();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="font-weight: bold; color: rgb(255, 153, 0);"&gt;&lt;span style="font-size:180%;"&gt;PROPIEDADES&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;1.- animationType:Function&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Propiedad que lleva como referencia el tipo de animación, las  siguientes opciones son las que puedes usar, para utilizarlas tienes que  importar el paquete mx.transitions.tween.easing.*&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Strong.easeIn, Strong.easeOut, Strong.easeInOut&lt;/li&gt;&lt;li&gt;Back.easeIn, Back.easeOut, Back.easeInOut&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Bounce.easeIn, Bounce.easeOut, Bounce.easeInOut&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Regular.easeIn, Regular.easeOut, Regular.easeInOut&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Elasctic.easeIn, Elasctic.easeOut, Elasctic.easeInOut&lt;br /&gt;&lt;/li&gt;&lt;li&gt;None.easeNone&lt;/li&gt;&lt;/ul&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.animationType = Bounce.easeInOut;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;2.- direction:IDirection&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Esto es la dirección que va a tomar la animación, por  ejemplo, puede ir de izquierda a derecha ó de derecha a izquierda, las  siguientes direcciones son las disponibles en el paquete, se tiene que importar  el paquete com.jahepi.squareeffect.directions.*:&lt;br /&gt;&lt;/p&gt;&lt;ul type="disc"&gt;&lt;li&gt;UptoDown&lt;/li&gt;&lt;li&gt;DowntoUp&lt;/li&gt;&lt;li&gt;LefttoRight&lt;/li&gt;&lt;li&gt;RighttoLeft&lt;/li&gt;&lt;li&gt;DowntoUpCornerLeft&lt;/li&gt;&lt;li&gt;DowntoUpCornerRight&lt;/li&gt;&lt;li&gt;UptoDownCornerLeft&lt;/li&gt;&lt;li&gt;UptoDownCornerRight&lt;/li&gt;&lt;li&gt;ZigZag&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.direction = new UptoDown(1, .2);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ahora los  objetos IDirection como UptoDown reciben 2 parámetros:&lt;/p&gt;&lt;p style="color: rgb(0, 153, 0);"&gt;Delay: Este  es el tiempo en segundos que va a transcurrir para que empiece la animación.&lt;/p&gt;&lt;p style="color: rgb(0, 153, 0);"&gt;DelayIncrementer:  Este es un poco confuso al principio, pero es la espera en segundos que se va a  incrementar por cada línea de animación generada por la dirección, hagan la  prueba para que vean el efecto.&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;3.- duration:Number&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Es el tiempo en segundos que va a durar la animación en cada  división del movieclip. &lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.duration = 2;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;4.- rows:Number&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Descripción:&lt;br /&gt;Número que indica el número de filas que será dividido el movieclip.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.rows = 13;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;5.- columns:Number&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Descripción:&lt;br /&gt;Número que indica el número de columnas que será dividido el movieclip.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.columns = 13;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;6.- fadeIn:Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Descripción:&lt;br /&gt;Booleano que indica si el efecto oculta el movieclip o lo muestra.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Ejemplo:&lt;br /&gt;effect.fadeIn = true;&lt;/code&gt;&lt;/pre&gt;&lt;p style="font-weight: bold; color: rgb(255, 102, 0);"&gt;&lt;span style="font-size:180%;"&gt;EVENTOS&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(204, 0, 0);"&gt;1.- ON_MOTION_FINISH&lt;/p&gt;&lt;p&gt;Descripción:&lt;br /&gt;Evento que nos notifica cuando la animación ha terminado.&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;effect.addEventListener(MaskSquareEffect.ON_MOTION_FINISH, onFinish);&lt;br /&gt;&lt;br /&gt;function onFinish(evt:Object):Void {&lt;br /&gt;   evt.target.remove();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;El evento nos devuelve un objeto que tiene una propiedad  target que hace referencia al objeto MaskSquareEffect.&lt;/p&gt;&lt;p&gt;Ahora veamos un ejemplo completo:&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import com.jahepi.squareeffect.MaskSquareEffect;&lt;br /&gt;import mx.transitions.easing.*;&lt;br /&gt;import com.jahepi.squareeffect.directions.*;&lt;br /&gt;&lt;br /&gt;var effect:MaskSquareEffect = new MaskSquareEffect(mc, 10, 15, true);&lt;br /&gt;effect.animationType = Elastic.easeOut;&lt;br /&gt;effect.duration = 1;&lt;br /&gt;effect.direction = new ZigZag(1, .05);&lt;br /&gt;effect.addEventListener(MaskSquareEffect.ON_MOTION_FINISH, onFinish);&lt;br /&gt;effect.play();&lt;br /&gt;&lt;br /&gt;function onFinish(evt:Object):Void {&lt;br /&gt;   evt.target.remove();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sencillo, no ?, si  quieren pueden agregarle mas tipos de direcciones para eso métanle mano al  paquete com.jahepi.squareeffect.directions, ahí viene la clave.&lt;/p&gt;Dentro del archivo, viene un ejemplo para que vean el funcionamiento.&lt;br /&gt;&lt;p&gt;Sale, cualquier duda, comentario, mejoras, etc., se los  agradecería muchísimo.&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight: bold;"&gt;Un saludote !&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-7638515765372390975?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/7638515765372390975/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=7638515765372390975' title='2 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/7638515765372390975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/7638515765372390975'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2008/06/clase-para-hacer-efecto-de-cuadros.html' title='Librería MaskSquareEffect - ActionScript 2.0'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-28614045265317529</id><published>2008-06-16T12:14:00.000-07:00</published><updated>2008-12-10T17:17:58.058-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Proyectos'/><title type='text'>Simulador de Explorador de Carpetas (XML+AS3.0)</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Hola !&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Traigo un pequeño proyecto que estaba haciendo en mis tiempos libres, es un simple simulador de explorador de carpetas hecho en Flash CS3, utiliza XML y Actionscript 3.0.&lt;br /&gt;&lt;br /&gt;Se podría utilizar para hacer catálogos ó portafolios de trabajos, la ventaja es que puedes hacer una estructura anidada de los niveles que gustes, cada carpeta puede contener sus propios archivos, también le incorporé una paginación cuando se despliegan los archivos, ordenamiento por nombre pero se le pueden añadir nuevos filtros de ordenamiento fácilmente como ordenar los archivos por su fecha si es que decides agregarle esa propiedad, el ordenamiento es muy parecido a la arquitectura utilizada en java.&lt;br /&gt;&lt;br /&gt;Explico como utilizar el proyecto por defecto.&lt;br /&gt;&lt;br /&gt;Descomprime el proyecto, vas a ver una carpeta model, dentro de esta contiene un archivo llamado &lt;span style="font-weight: bold;"&gt;“categorias.xml”&lt;/span&gt;, en esta viene la configuración de las carpetas, veamos el xml:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;categorias&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;categoria nombre="Carpeta 1" src="model/data/datosCarpeta.xml"&amp;gt;&lt;br /&gt;    &amp;lt;categoria nombre="SubCarpeta 1-A" src="model/data/datosCarpeta.xml"&amp;gt;&lt;br /&gt;        &amp;lt;categoria nombre="SubSubCarpeta 1-A-A" src="model/data/datosCarpeta.xml" /&amp;gt;&lt;br /&gt;    &amp;lt;/categoria&amp;gt;&lt;br /&gt;    &amp;lt;categoria nombre="SubCarpeta 1-B" src="model/data/datosCarpeta.xml" /&amp;gt;&lt;br /&gt; &amp;lt;/categoria&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;categoria nombre="Carpeta 2" src=""&amp;gt;&lt;br /&gt;    &amp;lt;categoria nombre="SubCarpeta 2-A" src="model/data/datosCarpeta.xml" /&amp;gt;&lt;br /&gt; &amp;lt;/categoria&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/categorias&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Dentro de la etiqueta &lt;categorías&gt;, se encuentra la estructura general de las carpetas, por ejemplo:&lt;br /&gt;&lt;br /&gt;Tengo 2 carpetas en la raíz de mi proyecto,&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Carpeta 1&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Carpeta 2&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Dentro de Carpeta 1 hay una carpeta llamada SubCarpeta 1-A y Subcarpeta 2-A, dentro de SubCarpeta 1-A encontramos que hay otra carpeta SubSubCarpeta 1-A-A y dentro de SubSubCarpeta 1-A-A ya no hay nada.&lt;br /&gt;&lt;br /&gt;Dentro de Carpeta 2 hay una carpeta llamada SubCarpeta 2-A, y esta carpeta ya no contiene otras carpetas.&lt;br /&gt;&lt;br /&gt;Así podemos ir anidando las carpetas los niveles que deseemos.&lt;br /&gt;&lt;br /&gt;Dentro de cada carpeta podemos tener archivos, y para lograr esto, utilizamos el atributo &lt;span style="font-weight: bold;"&gt;“src”&lt;/span&gt; de la etiqueta &lt;categoría&gt;, dentro de este atributo ponemos la ruta que contiene los archivos, si esa carpeta no contiene archivos dejamos ese atributo en blanco.&lt;br /&gt;&lt;br /&gt;Por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;categoria nombre="Carpeta 1" src="model/data/datosCarpeta.xml"&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La Carpeta 1, cuando la abramos cargará los archivos que se encuentran en model/data/datosCarpeta.xml, la estructura de ese archivo debe ser como esta:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;categoryData&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;data&amp;gt;&lt;br /&gt;     &amp;lt;name&amp;gt;Homer Jay&amp;lt;/name&amp;gt;&lt;br /&gt;     &amp;lt;desc&amp;gt;La voz original en inglés es de Dan Castellaneta. En España fue doblado hasta la undécima temporada por el fallecido Carlos Revilla, a quien sustituye Carlos Ysbert. En Latinoamérica hasta la decimoquinta temporada (incluida) estaba doblado por Humberto Vélez, reemplazado tiempo después por Otto Balbuena.&amp;lt;/desc&amp;gt;&lt;br /&gt;     &amp;lt;views&amp;gt;&lt;br /&gt;        &amp;lt;view&amp;gt;images/homero.gif&amp;lt;/view&amp;gt;&lt;br /&gt;     &amp;lt;/views&amp;gt;&lt;br /&gt;   &amp;lt;/data&amp;gt;&lt;br /&gt;  &lt;br /&gt;   &amp;lt;data&amp;gt;&lt;br /&gt;     &amp;lt;name&amp;gt;Bartholomew&amp;lt;/name&amp;gt;&lt;br /&gt;     &amp;lt;desc&amp;gt;Bart es decididamente el más rebelde de la familia. Es un muchacho simpático y también muy travieso, que hace muchas bromas con su amigo Milhouse. Sigue los programas de su ídolo Krusty el payaso y de Itchy &amp;amp; Scratchy.&amp;lt;/desc&amp;gt;&lt;br /&gt;     &amp;lt;views&amp;gt;&lt;br /&gt;        &amp;lt;view&amp;gt;images/bart.jpg&amp;lt;/view&amp;gt;&lt;br /&gt;     &amp;lt;/views&amp;gt;&lt;br /&gt;   &amp;lt;/data&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;categoryData&amp;gt;   &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando queramos agregar nuevos archivos agregamos un nuevo nodo “data”, algo muy importante es no olvidar poner la etiqueta &lt;views&gt;, dentro de esta van las imágenes por si tu archivo hace referencia a un juego de imágenes, puedes poner swf´s, jpg´s, gif´s ó png´s.&lt;br /&gt;&lt;br /&gt;Si no hay imágenes deja la etiqueta views vacía.&lt;br /&gt;&lt;br /&gt;Así cada carpeta puede apuntar a un archivo diferente en su atributo src, siempre y cuando respetando la estructura del xml que contiene los archivos.&lt;br /&gt;&lt;br /&gt;Sale, dejo el proyecto, para que le metan mano y lo acoplen a sus necesidades.&lt;br /&gt;&lt;br /&gt;Cualquier comentarios, sugerencia, mentada de madre :P, es bienvenida.&lt;br /&gt;&lt;br /&gt;Les dejo una captura:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__ZhsAyyhgGg/SFa9oR_RIhI/AAAAAAAAABc/Ivgcxie35UE/s1600-h/ejemplo.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/__ZhsAyyhgGg/SFa9oR_RIhI/AAAAAAAAABc/Ivgcxie35UE/s400/ejemplo.JPG" alt="" id="BLOGGER_PHOTO_ID_5212562118449111570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Aquí se pueden descargar el proyecto:&lt;br /&gt;&lt;a href="http://www.mediafire.com/?xx7y9x2lzw2"&gt;PROYECTO&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Un Saludote !&lt;/span&gt;&lt;/views&gt;&lt;/categoría&gt;&lt;/categorías&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-28614045265317529?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/28614045265317529/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=28614045265317529' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/28614045265317529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/28614045265317529'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2008/06/simulador-de-explorador-de-carpetas.html' title='Simulador de Explorador de Carpetas (XML+AS3.0)'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/__ZhsAyyhgGg/SFa9oR_RIhI/AAAAAAAAABc/Ivgcxie35UE/s72-c/ejemplo.JPG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-4177948327412003167</id><published>2008-06-06T14:42:00.000-07:00</published><updated>2008-12-10T17:18:31.764-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño Orientado a Objetos'/><title type='text'>Una nueva forma de ver el paradigma orientado a objetos - Parte 2</title><content type='html'>&lt;span style="font-size:180%;"&gt;Encapsulamiento: la forma tradicional de verlo y la nueva forma de verlo&lt;/span&gt;  &lt;h4&gt;&lt;i&gt;Mi paraguas orientado a objetos.&lt;o:p&gt;&lt;/o:p&gt;&lt;/i&gt;&lt;/h4&gt;  &lt;p&gt;En mi clases de diseño de orientado a objetos, frecuentemente pregunto a mis estudiantes, “Quien ha escuchado que encapsulamiento es definido como ocultamiento de datos?”, casi todos levantan la mano.&lt;/p&gt;  &lt;p&gt;Entonces procedo a contar una historia de mi paraguas. Ten en mente que vivo en Seatle, la cual tiene una reputación de ser más húmedo de lo que es, pero es aún un lugar muy húmedo en otoño, invierno y primavera. Aquí los paraguas y abrigos son nuestros amigos personales!&lt;/p&gt;  &lt;p&gt;Déjame contarte acerca de mi gran paraguas. Es bastante grande para cubrirme!, de hecho, 3 o 4 personas puedes cubrirse conmigo. Mientras estamos cubiertos, manteniéndonos alejados de la lluvia, puedo moverme de un lugar a otro. Tiene un sistema de sonido para mantenerme entretenido mientras me mantengo seco. Sorprendentemente, puede también acondicionar el aire para que este más caliente o más frío. &lt;span style="" lang="EN-US"&gt;Es un paraguas genial.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;Mi paraguas es conveniente.&lt;span style=""&gt;  &lt;/span&gt;Se queda ahí esperando por mi. Tiene ruedas para que no tenga que estarlo cargando. Ni siquiera lo tengo que empujar porque lo puede hacer por si mismo. Algunas veces, abriré la parte superior de mi paraguas para dejar pasar los rayos solares. (El porque del que este usando mi paraguas cuando esta asoleado afuera esta fuera de mi compresión).&lt;/p&gt;  &lt;p&gt;En Seatle, hay cientos de miles de paraguas de todos colores.&lt;/p&gt;  &lt;p&gt;La mayoría de las personas les llama autos.&lt;/p&gt;  &lt;p&gt;Pero pienso en el mío como un paraguas porque un paraguas es algo usado para mantenernos fuera de la lluvia. Muchas veces, mientras estoy esperando afuera por alguien para conocerlo, me siento en mi “paraguas” para mantenerme seco!&lt;/p&gt;  &lt;h4&gt;&lt;i&gt;Las definiciones pueden limitarnos&lt;o:p&gt;&lt;/o:p&gt;&lt;/i&gt;&lt;/h4&gt;  &lt;p&gt;Por supuesto que un carro no es realmente un paraguas. Si, puedes usarlo para mantenerte alejado de la lluvia, pero esa es una visión muy limitada de un auto. De la misma manera, el encapsulamiento es no solamente para el ocultamiento de datos. Esa es una visión muy limitada de encapsulamiento. Pensarlo de esa manera nos limita al hacer nuestros diseños. &lt;/p&gt;  &lt;h4&gt;&lt;i&gt;Como pensar acerca del encapsulamiento&lt;/i&gt;&lt;/h4&gt;  &lt;p&gt;Encapsulamiento debería ser enseñado como “cualquier tipo de ocultamiento”. En otras palabras, puede ocultar datos. Pero también puede ocultar implementaciones, clases derivadas o cualquier cantidad de cosas. &lt;span style="" lang="EN-US"&gt;Considera el diagrama monstrado en la figura 8-1. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;h4&gt;&lt;i&gt;&lt;span style="" lang="EN-US"&gt;Multiples niveles de encapsulamiento &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/i&gt;&lt;/h4&gt;  &lt;p class="MsoNormal"&gt;Figura 8-1&lt;/p&gt;  &lt;h4&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__ZhsAyyhgGg/SEmwMcvGcfI/AAAAAAAAABM/L4Yg8wEFRQw/s1600-h/08fig01.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/__ZhsAyyhgGg/SEmwMcvGcfI/AAAAAAAAABM/L4Yg8wEFRQw/s400/08fig01.gif" alt="" id="BLOGGER_PHOTO_ID_5208888171949355506" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;i&gt;&lt;span style="" lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/i&gt;&lt;/h4&gt;  &lt;p&gt;La figura 8-1 muestra varios tipos de encapsulamiento:&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Encapsulamiento de datos – Los datos en Point, Line, Saquer y Circle están ocultos.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Encapsulamiento de métodos – Por ejemplo, el método setLocation de Circle.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Encapsulamiento de Subclases – Los clientes de Shape no ven Points, Lines, Squares o Circles.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;!--[if !supportLists]--&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Encapsulamiento de otros objetos: Nadie más que Circle esta enterado de la existencia de xxCircle.&lt;/p&gt;  &lt;p&gt;Un tipo de encapsulamiento es alcanzado cuando hay una clase abstracta que se comporta polifórmicamente sin que el cliente se entere de que tipo en concreto es el que está usando. Además, adaptando interfaces oculta lo que esta detrás del objeto adaptado.&lt;/p&gt;  &lt;h4&gt;&lt;i&gt;La ventaja de esta nueva definición&lt;/i&gt;&lt;/h4&gt;  &lt;p&gt;La ventaje de ver el encapsulamiento de esta manera nos da una mejor manera de separar (descomponer) los programas. Las capas de encapsulamiento llegan a ser las interfaces que debo diseñar. Encapsulando varios tipos de Shapes, puedo añadir nuevos sin cambiar nada del programa del cliente que los usa. Encapsulando XXCircle detrás de Circle, puedo cambiar la implementación en un futuro si lo eligo o es necesario. &lt;/p&gt;  &lt;h4&gt;&lt;i&gt;Herencia como concepto vs herencia para la reutilización&lt;/i&gt;&lt;/h4&gt;  &lt;p&gt;Cuando el paradigma orientado a objetos fue por primera vez presentado, la reutilización de clases fue promocionada como uno de los más grandes beneficios. La reutilización usualmente era lograda creando clases y luego derivando nuevas clases basadas en las clases base. Por lo tanto el término clases especializadas era para esas subclases que fueron derivadas de otras clases (otras clases se refiere también a un término conocido como clases generalizadas).&lt;/p&gt;  &lt;p&gt;No estoy poniendo en duda la importancia de esto, en lugar estoy proponiendo lo que creo es una forma más poderosa de usar la herencia. En el ejemplo de arriba, puedo hacer mis diseños basados en diferentes tipos especiales de Shapes (Estos son, Points, Lines, Squares y Circles). Sin embargo, esto probablemente no oculte los casos especiales cuando yo piense en usar Shapes. Puede que tome ventaja del conocimiento de estas clases concretas.&lt;/p&gt;  &lt;p&gt;Si por el contrario, pienso en Shapes como una forma de clasificar Points, Lines Squares y Circles, puedo más fácilmente pensar acerca de estos como un TODO. Esto hará más probable que yo diseñe por interfaz (Shapes). También significa que si obtengo un nuevo tipo de Shape, será poco probable que me vea en una posición de dificultad de mantenimiento. (Porque el código del cliente no conoce con que tipo en concreto de Shape está tratando).&lt;/p&gt;&lt;p&gt;&lt;/p&gt;Pronto pondré la tercera parte,&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Un saludote !&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-4177948327412003167?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/4177948327412003167/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=4177948327412003167' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/4177948327412003167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/4177948327412003167'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2008/06/una-nueva-forma-de-ver-el-paradigma.html' title='Una nueva forma de ver el paradigma orientado a objetos - Parte 2'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/__ZhsAyyhgGg/SEmwMcvGcfI/AAAAAAAAABM/L4Yg8wEFRQw/s72-c/08fig01.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-586370534165057508</id><published>2008-05-27T15:31:00.000-07:00</published><updated>2008-12-15T15:31:16.446-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Análisis y Diseño Orientado a Objetos'/><title type='text'>Una nueva forma de ver el paradigma orientado a objetos - Parte 1</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Hola !&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Les traigo una traducción que aún estoy elaborando de un capítulo del libro &lt;a href="http://www.amazon.com/Design-Patterns-Explained-Perspective-Object-Oriented/dp/0201715945"&gt;Design Patterns Explained&lt;/a&gt;, es uno de los capítulos que me ha parecido extraordinario, ire subiendo fragmentos progresivamente, espero que este pequeño tema los anime a conseguir este excelente libro.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Una Nueva Perspectiva&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;La forma tradicional de ver los objetos, encapsulamiento y herencia es muy limitada. En este capítulo de “Design Patterns Explained”, lo autores describen una nueva forma de ver el diseño orientado a objetos, la cual viene de una perspectiva tomada de los patrones de diseño.&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-weight: bold;"&gt;Introducción&lt;/p&gt;  &lt;p&gt;En capítulos anteriores, se discutieron 3 conceptos fundamentales del diseño orientado a objetos: objetos, encapsulación, y clases abstractas. Como el diseñador ve estos conceptos es importante. La forma tradicional de verlo es simplemente muy limitada. En este capítulo se da un paso atrás y nos enfocamos en temas discutidos anteriormente en este libro. La intención es describir una nueva forma de ver el diseño orientado a objetos, la cual viene de una perspectiva tomada de los patrones de diseño.&lt;/p&gt;  &lt;p&gt;En este capítulo:&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Comparo y contrasto la forma tradicional de ver a los objetos, como un paquete de datos y métodos, con la nueva forma, como cosas con responsabilidades.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Comparo y contrasto la forma tradicional de ver al encapsulamiento como ocultamiento de datos, con la nueva forma como la habilidad de ocultar cualquier cosa. Es especialmente importante ver que el encapsulamiento puede ser usado para contener variaciones en el comportamiento.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Comparo y contrasto la forma tradicional de ver a la herencia, para especialización y reutilización con la nueva forma, como un método para clasificar objetos.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Los nuevos puntos de vista permiten contener variaciones en el comportamiento de los objetos.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Muestro como la perspectiva conceptual, de especificación y de implementación se relacionan con las clases abstractas y sus clases derivadas.&lt;/p&gt;  &lt;p&gt;Quizás esta nueva perspectiva no es del todo original. Creo que esta perspectiva es una que muchos desarrolladores de patrones de diseño mantienen cuando ellos desarrollan lo que podría ser lo que todos conocemos como un patrón. Ciertamente, es una perspectiva que es consistente con los escritos de Christopher Alexander, Jim Coplien, y las Pandilla de los cuatro.&lt;/p&gt;  &lt;p&gt;Cuando lo llamo una nueva perspectiva, lo que quiero decir es que probablemente sea una nueva forma para la mayoría de los desarrolladores &lt;span style=""&gt; &lt;/span&gt;de ver los objetos. Ciertamente fue una nueva forma para mí cuando estaba aprendiendo patrones de diseño la primera vez.&lt;/p&gt;  &lt;h2&gt;Objetos: La forma tradicional de verlos y la nueva forma.&lt;/h2&gt;  &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;La forma tradicional de verlos: datos y métodos&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;La forma tradicional de ver los objetos es que son datos y métodos. Uno de mis maestros los llamaba “datos inteligentes”. Es solamente un paso adelante de las bases de datos. Esta manera de verlos viene de la forma de ver los objetos en la perspectiva de implementación.&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;La nueva forma de verlos: cosas con responsabilidades&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;Mientras que esta definición es acertada, explicada en el capítulo 1, El paradigma orientado a objetos, está basado en la perspectiva de implementación. Una definición más útil es la basada en la perspectiva conceptual, un objetos es una entidad que tiene responsabilidades. Estas responsabilidades dan al objeto su comportamiento. A veces, también pienso que un objeto es una entidad que tiene un comportamiento específico.&lt;/p&gt;  &lt;p&gt;Esta es una mejor definición porque ayuda a enfocarse en lo que deben de hacer los objetos, y no simplemente en como implementarlos. &lt;span style="" lang="EN-US"&gt;Esto me permite construir el software en 2 pasos:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Hacer un diseño preliminar sin preocuparme de todos los detalles involucrados.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Implementar el diseño conseguido.&lt;/p&gt;  &lt;p&gt;Finalmente, esta perspectiva permite una mejor selección y definición de los objetos (en cierto sentido, el principal punto del diseño). La definición de un objeto es más flexible; enfocándonos en lo que el objeto hace, la herencia nos permite utilizar diferentes, comportamientos específicos cuando sean necesarios. Un enfoque en la implementación puede que alcancemos esto, pero la flexibilidad típicamente viene a un alto precio.&lt;/p&gt;  &lt;p&gt;Es más fácil pensar en términos de responsabilidades porque ayuda a definir la interfaz pública del objeto. Si un objeto tiene una responsabilidad, debe de haber alguna manera de preguntarle que haga su responsabilidad. Sin embargo, no implica nada acerca de lo que hay dentro del objeto. La información de la cual el objeto es responsable puede que no este ni siquiera adentro de el mismo.&lt;/p&gt;  &lt;p&gt;Por ejemplo, supongamos que tenemos un objeto Shape y sus responsabilidades son:&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Saber donde esta posicionado.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Capaz de dibujarse así mismo es una pantalla.&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style="font-family:Symbol;"&gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Capaz de removerse así mismo de una pantalla.&lt;/p&gt;  &lt;p&gt;Estas responsabilidades implican que un conjunto particular de métodos debe existir:&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style=";font-family:Symbol;font-size:10;"  &gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;span style="font-size:10;"&gt;getLocation( ... )&lt;/span&gt;&lt;/tt&gt;&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style=";font-family:Symbol;font-size:10;"  &gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;span style="font-size:10;"&gt;drawShape( ... )&lt;/span&gt;&lt;/tt&gt;&lt;/p&gt;  &lt;p style="margin-left: 36pt; text-indent: -18pt;"&gt;&lt;span style=";font-family:Symbol;font-size:10;"  &gt;&lt;span style=""&gt;·&lt;span style=""&gt;         &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;span style="font-size:10;"&gt;unDrawShape( ... )&lt;/span&gt;&lt;/tt&gt;&lt;/p&gt;  &lt;p&gt;No hay implicación acerca de los que hay dentro de Shape. Solamente me importa que Shape sea responsable de sus propios comportamientos. Puede que tenga atributos dentro de el o puede que tenga métodos que hacen cálculos o inclusive se refieran a otros objetos.&lt;span style=""&gt;  &lt;/span&gt;Aunque, Shape podría contener atributos de su localización actual o podría referirse a otro objeto de una base de datos para obtener su localización. Esto nos da la flexibilidad que se necesita para alcanzar nuestros objetivos de modelado. &lt;/p&gt;  &lt;p&gt;Es interesante, encontrarás que enfocarnos en la motivación en lugar de la implementación es un tema recurrente en el diseño de patrones.&lt;/p&gt;  &lt;p&gt;Mira a los objetos de esta manera. Hazlo tu principal punto de vista de los objetos. Si lo haces, tendrás diseños superiores.&lt;/p&gt;Fin de la parte 1, pronto publicaré la parte 2.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Un Saludote !&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-586370534165057508?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/586370534165057508/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=586370534165057508' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/586370534165057508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/586370534165057508'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2008/05/una-nueva-forma-de-ver-el-paradigma.html' title='Una nueva forma de ver el paradigma orientado a objetos - Parte 1'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-3634449430310380619</id><published>2007-10-11T19:23:00.000-07:00</published><updated>2008-12-10T16:48:04.848-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Patrones de Diseño'/><title type='text'>Patrón Decorador - ActionScript 3.0</title><content type='html'>Supongamos que estamos diseñando un juego de rol, y nuestros personajes pueden tener espadas, estas pueden ser fusionadas con gemas de varios tipos para mejorarlas, por ejemplo para darle más fuerza de ataque o más velocidad, bueno nosotros muy contentos hacemos nuestra interfaz para nuestras espadas, quedaría codificada de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;1 package {&lt;br /&gt;2&lt;br /&gt;3   public interface ISword {&lt;br /&gt;4     function render():String;&lt;br /&gt;5   }&lt;br /&gt;6 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Es una interfaz muy sencilla, el método render se encarga de construir la espada y mostrarla en la salida de pantalla. Al utilizar una interfaz en un clase se está firmando un contrato de implementación, esto quiere decir que es obligatorio implementar (valga la redundancia) los métodos que se encuentran en la firma en este caso "render".&lt;br /&gt;&lt;br /&gt;Ahora vamos a crear nuestras espadas (implementaciones concretas), por el momento vamos a hacer 2 que puedan usar los personajes del juego de rol.&lt;br /&gt;&lt;br /&gt;La primera la llamaremos Sword of Azure:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1 package {&lt;br /&gt;2    public class SwordOfAzure implements ISword {&lt;br /&gt;3&lt;br /&gt;4      public function render():String {&lt;br /&gt;5         return "Rendering SwordOfAzure SWORD.";&lt;br /&gt;6      }&lt;br /&gt;7    }&lt;br /&gt;8 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y la segunda se llamará Sword of Kyrlin:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;1 package {&lt;br /&gt;2     public class SwordOfKyrlin implements ISword {&lt;br /&gt;3&lt;br /&gt;4       public function render():String {&lt;br /&gt;5         return "Rendering SwordOfKyrlin SWORD.";&lt;br /&gt;6       }&lt;br /&gt;7     }&lt;br /&gt;8 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Felices y contentos ya tenemos nuestras 2 super espadotas para nuestros personajes, pero ahora se nos ha ocurrido un gran idea, porque no fusionamos las espadas con gemas para que nos den puntos de ataque, agilidad o otras cosillas interesantes, por ejemplo, fusionarla con una gema roja de ataque para que le de +4 puntos de ataque ó una gema azul para que le de +4 puntos de agilidad, o hasta se puede dar la situación que se fusionen las 2 gemas para que le de +4 de ataque y +4 de agilidad.&lt;br /&gt;&lt;br /&gt;Nosotros pensamos, mmm... vamos a crear nuestras espadas modificadas heredando de SwordOfAzure y SwordOfKyrlin, así que nos ponemos a hacer cada una de las combinaciones posibles.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;1 class SwordOfAzureRedGem extends SwordOfAzure {&lt;br /&gt;2 }&lt;br /&gt;3&lt;br /&gt;4 class SwordOfAzureBlueGem extends SwordOfAzure {&lt;br /&gt;5 }&lt;br /&gt;6&lt;br /&gt;7 class SwordOfAzureBlueGemAndRedGem extends SwordOfAzure {&lt;br /&gt;8 }&lt;br /&gt;9&lt;br /&gt;10 class SwordOfKrylinRedGem extends SwordOfKrylin {&lt;br /&gt;11 }&lt;br /&gt;12&lt;br /&gt;13 class SwordOfKrylinBlueGem extends SwordOfKrylin {&lt;br /&gt;14 }&lt;br /&gt;15&lt;br /&gt;16 class SwordOfKrylinBlueGemAndRedGem extends SwordOfKrylin {&lt;br /&gt;17 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Dejemos los detalles de implementación a un lado.&lt;br /&gt;&lt;br /&gt;Aquí vemos que empieza a surgir un problema, el número de clases se ira incrementando de manera excesiva cuando vayamos agregando más espadas y más estilos de gemas a nuestro juego, serían demasiadas clases !!&lt;br /&gt;&lt;br /&gt;Aquí es donde entra el patrón decorador al rescate, este nos deja extender la funcionalidad de un objeto en tiempo de ejecución de esta manera estaríamos extendiendo la funcionalidad de nuestras espadas sin recurrir a la herencia, este patrón se basa simplemente en la composición de objetos, ahora verás el porqué.&lt;br /&gt;&lt;br /&gt;Veamos el diagrama de cómo está estructurado el patrón decorador:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/en/thumb/e/e9/Decorator_Pattern_ZP.svg/400px-Decorator_Pattern_ZP.svg.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px;" src="http://upload.wikimedia.org/wikipedia/en/thumb/e/e9/Decorator_Pattern_ZP.svg/400px-Decorator_Pattern_ZP.svg.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Como vemos en el diagrama, “Component” puede ser una clase abstracta o una interfaz, en este caso es nuestra interfaz ISword y los “ConcreteComponent”, son nuestras espadas que implementan las interfaz ISword.&lt;br /&gt;&lt;br /&gt;Como dice el diagrama “Decorator” debe ser una clase abstracta que implemente la interfaz “Component” y que esta encapsule la referencia de cualquier objeto que sea un “Component”, ósea que nuestro Decorador debe implementar la interfaz ISword y esta debe de tener una propiedad que apunte a un objeto del tipo ISword.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;1 package {&lt;br /&gt;2    /**&lt;br /&gt;3     * ABSTRACT CLASS&lt;br /&gt;4     */&lt;br /&gt;5     public class SwordDecorator implements ISword {&lt;br /&gt;6&lt;br /&gt;7&lt;br /&gt;8        protected var _decorated:ISword;&lt;br /&gt;9&lt;br /&gt;10&lt;br /&gt;11       public function SwordDecorator(decorated:ISword) {&lt;br /&gt;12          _decorated = decorated;&lt;br /&gt;13       }&lt;br /&gt;14&lt;br /&gt;15    /**&lt;br /&gt;16     * Abstract Method&lt;br /&gt;17     * Debe ser implementado en las subclases&lt;br /&gt;18     */&lt;br /&gt;19       public function render():String {&lt;br /&gt;20          return "";&lt;br /&gt;21       }&lt;br /&gt;22    }&lt;br /&gt;23 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El método render debe ser abstracto para que sea implementato en los decoradores, como AS3.0 todavía no soporta ni las clases abstractas ni los métodos abstractos, le he puesto un comentario y una implementación por defecto, pero ese método deber ser sobreescrito en sus decoradores (subclases).&lt;br /&gt;&lt;br /&gt;Así que vamos a crear nuestros primer decorador:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;1 package {&lt;br /&gt;2    /**&lt;br /&gt;3     * Esta Gema nos da +4 puntos de agilidad a nuestra espada.&lt;br /&gt;4     */&lt;br /&gt;5     public class BlueGem extends SwordDecorator {&lt;br /&gt;6&lt;br /&gt;7        public function BlueGem(decorated:ISword) {&lt;br /&gt;8           super(decorated);&lt;br /&gt;9        }&lt;br /&gt;10&lt;br /&gt;11       override public function render():String {&lt;br /&gt;12          calculateSomethingImportant();&lt;br /&gt;13          return _decorated.render() + " , +4 puntos de agilidad";&lt;br /&gt;14       }&lt;br /&gt;15&lt;br /&gt;16      /**&lt;br /&gt;17       * Método que hace un cáculo&lt;br /&gt;18       */&lt;br /&gt;19       private function calculateSomethingImportant():void {&lt;br /&gt;20           //...&lt;br /&gt;21       }&lt;br /&gt;22    }&lt;br /&gt;23 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y este es nuestro segundo decorador:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;1 package {&lt;br /&gt;2    /**&lt;br /&gt;3     * Esta Gema nos da +4 puntos de ataque a nuestra espada.&lt;br /&gt;4     */&lt;br /&gt;5     public class RedGem extends SwordDecorator {&lt;br /&gt;6&lt;br /&gt;7        public function RedGem(decorated:ISword) {&lt;br /&gt;8            super(decorated);&lt;br /&gt;9        }&lt;br /&gt;10&lt;br /&gt;11       override public function render():String {&lt;br /&gt;12           return _decorated.render() + " , +4 puntos de ataque";&lt;br /&gt;13       }&lt;br /&gt;14    }&lt;br /&gt;15 }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ve como en las 2 clases he heredado de la clase Abstracta SwordDecorator, y en el constructor le paso la referencia de un objeto del tipo ISword, aquí una cosa muy importante es ver como en cada clase concreta se implementó el método render ya que es un método abstracto de la super clase y observa como llamo al método render del objeto que se paso como argumento en el constructor (_decorated) y de acuerdo a lo que me devuelva, hago una implementación nueva, en este caso le añadí una nueva cadena a la cadena que nos devuelve el objeto decorado.&lt;br /&gt;&lt;br /&gt;El código de la parte del cliente se vería así:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;1 var mySword:ISword = new SwordOfKyrlin();&lt;br /&gt;2 mySword = new RedGem(mySword);&lt;br /&gt;3 mySword = new BlueGem(mySword);&lt;br /&gt;4 trace(mySword.render());&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como vemos a nuestra espada la hemos fusionado con 2 gemas y le hemos añadido funcionalidades diferentes, si comparamos el número de clases de la primera solución con esta última, es una GRAN diferencia, nosotros podemos agregar más decoradores y espadas sin mucho problema.&lt;br /&gt;&lt;br /&gt;Cualquier duda, comentario o sugerencia es bienvenida.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Un Saludote !&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-3634449430310380619?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/3634449430310380619/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=3634449430310380619' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/3634449430310380619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/3634449430310380619'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2007/10/decorando-objetos-con-el-patrn.html' title='Patrón Decorador - ActionScript 3.0'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-942739315884543009</id><published>2007-09-30T19:01:00.000-07:00</published><updated>2008-12-10T17:14:13.314-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Patrones de Diseño'/><title type='text'>Patrón Iterador – ActionScript 3.0</title><content type='html'>Cuando tenemos colecciones de objetos a veces es necesario iterar sobre estos pero sin exponer su implementación interna, supongamos que tenemos una colección que la queremos solamente para que almacene cadenas:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2    &lt;br /&gt;3   public class StringCollection {&lt;br /&gt;4       &lt;br /&gt;5         private var _strings:Array;&lt;br /&gt;6 &lt;br /&gt;7         public function StringCollection() {&lt;br /&gt;8            _strings = new Array();&lt;br /&gt;9         }&lt;br /&gt;10 &lt;br /&gt;11         public function addElement(value:String):void {&lt;br /&gt;12            _strings.push(value);&lt;br /&gt;13         }&lt;br /&gt;14 &lt;br /&gt;15      }&lt;br /&gt;16   }&lt;br /&gt;17 &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como vemos nuestra colección tiene un método addElement que tiene la tarea de añadir cadenas al array “_strings”. Lo interesante en este caso es como podemos accesar al array “_strings” para poder iterar sobre sus valores. Una opción sería poner un método accesor en la clase, algo como esto:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2    &lt;br /&gt;3   public class StringCollection {&lt;br /&gt;4       &lt;br /&gt;5         private var _strings:Array;&lt;br /&gt;6 &lt;br /&gt;7         public function StringCollection() {&lt;br /&gt;8            _strings = new Array();&lt;br /&gt;9         }&lt;br /&gt;10 &lt;br /&gt;11         public function addElement(value:String):void {&lt;br /&gt;12            _strings.push(value);&lt;br /&gt;13         }&lt;br /&gt;14         //Método accesor al array&lt;br /&gt;15         public function get strings():Array {&lt;br /&gt;16            return _strings;&lt;br /&gt;17         }&lt;br /&gt;18 &lt;br /&gt;19      }&lt;br /&gt;20   }&lt;br /&gt;21 &lt;br /&gt;22    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y el cliente utilizaría nuestra clase así:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   var collection:StringCollection = new StringCollection();&lt;br /&gt;2   collection.addElement("cadena1");&lt;br /&gt;3   collection.addElement("cadena2");&lt;br /&gt;4   collection.addElement("cadena3");&lt;br /&gt;5   for(var i:Number = 0; i &amp;lt; collection.strings.length; i++) {&lt;br /&gt;6      trace(collection.strings[i]);&lt;br /&gt;7   }&lt;br /&gt;8 &lt;br /&gt;9 &lt;br /&gt;10  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Aquí hay 2 grandes problemas, estamos exponiendo los detalles de cómo debemos iterar sobre el arreglo y estamos rompiendo con el encapsulamiento al tener acceso directo al array, esto le da la oportunidad a cualquiera de poder cambiar algún valor del arreglo sin que nuestra clase se entere, que tal si en lugar de meter un string, le añado un entero ? (Recuerda que nuestra colección solamente debe almacenar cadenas).&lt;br /&gt;&lt;br /&gt;Bueno, entonces se nos ocurre meter la responsabilidad de iterar en la misma clase, quedaría así finálmente:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   public class StringCollection {&lt;br /&gt;2       &lt;br /&gt;3         private var _strings:Array;&lt;br /&gt;4         private var _index:Number;&lt;br /&gt;5 &lt;br /&gt;6         public function StringCollection() {&lt;br /&gt;7            _strings = new Array();&lt;br /&gt;8            _index = 0;&lt;br /&gt;9         }&lt;br /&gt;10 &lt;br /&gt;11         public function addElement(value:String):void {&lt;br /&gt;12            _strings.push(value);&lt;br /&gt;13         }&lt;br /&gt;14 &lt;br /&gt;15         public function reset():void {&lt;br /&gt;16            _index = 0;&lt;br /&gt;17         }&lt;br /&gt;18 &lt;br /&gt;19         public function hasNext():Boolean {&lt;br /&gt;20            return _index &amp;lt; _strings.length;&lt;br /&gt;21         }&lt;br /&gt;22 &lt;br /&gt;23         public function next():String {&lt;br /&gt;24            return _strings[_index++] as String;&lt;br /&gt;25         }&lt;br /&gt;26      }&lt;br /&gt;27   }&lt;br /&gt;28 &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pero nuevamente vemos problemas a la vista, supongamos que estamos en un sistema concurrente y tenemos 2 hilos que están iterando al mismo tiempo sobre la misma instancia de la colección, debido a que _index guarda la posición actual en el array, sería imposible iterar sobre la misma instancia. Otro problema vendría al querer definir nuevos tipos de iteración, por ejemplo en lugar de que la colección empiece de inicia a final, esta empiece de final a inicio, tendríamos que definir esos métodos que cumplan con esa tarea en la clase.&lt;br /&gt;&lt;br /&gt;Y principalmente estaríamos rompiendo con un principio de diseño, SRP o Single Responsability Principle, el cual nos dice que nuestra clase solamente debe tener UNA responsabilidad (Debe tener una sola razón de cambiar). Como vemos StringCollection tiene 2 responsabilidades, la de iterar sobre la colección y la parte de la gestión de la misma (añadir, remover, obtener, etc...).&lt;br /&gt;&lt;br /&gt;Como bien dice el sabio principio, “Encapsula lo que varíe”, en este caso la implementación de cómo iterar podría cambiar en un futuro no muy lejano.&lt;br /&gt;&lt;br /&gt;Así que vamos a separar eso y definamos nuestra interfaz que todos nuestros Iteradores van a implementar:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2      public interface IIterator {&lt;br /&gt;3         function next():Object;&lt;br /&gt;4         function hasNext():Boolean;&lt;br /&gt;5         function reset():void;&lt;br /&gt;6      }&lt;br /&gt;7   }&lt;br /&gt;8 &lt;br /&gt;9 &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El método next se encargará de devolvernos el siguiente objeto en la colección, hasNext nos devolvera true si todavía hay elementos en la colección o false en caso contrario, reset reiniciaría la posición del cursor en la colección.&lt;br /&gt;&lt;br /&gt;Ahora vamos a hacer 2 iteradores que la implementen, cada uno con sus implementaciones concretas del CÓMO iterar.&lt;br /&gt;&lt;br /&gt;Este es un iterador que recorre un Array de inicio a final:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2 &lt;br /&gt;3      public class ArrayIterator implements IIterator {&lt;br /&gt;4       &lt;br /&gt;5         private var _index:Number = 0;&lt;br /&gt;6         private var _collection:Array;&lt;br /&gt;7 &lt;br /&gt;8         public function ArrayIterator(collection:Array) {&lt;br /&gt;9            _collection = collection;&lt;br /&gt;10            _index = 0;&lt;br /&gt;11         }&lt;br /&gt;12 &lt;br /&gt;13         public function hasNext():Boolean {&lt;br /&gt;14            return _index &amp;lt; _collection.length;&lt;br /&gt;15         }&lt;br /&gt;16 &lt;br /&gt;17         public function next():Object {&lt;br /&gt;18            return _collection[_index++];&lt;br /&gt;19         }&lt;br /&gt;20 &lt;br /&gt;21         public function reset():void {&lt;br /&gt;22            _index = 0;&lt;br /&gt;23         }&lt;br /&gt;24 &lt;br /&gt;25      }&lt;br /&gt;26   }&lt;br /&gt;27 &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Este es un iterador que recorre un Array de final a inicio ósea en reversa:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2    &lt;br /&gt;3      public class ArrayReverseIterator implements IIterator {&lt;br /&gt;4 &lt;br /&gt;5         private var _index:Number = 0;&lt;br /&gt;6         private var _collection:Array;&lt;br /&gt;7 &lt;br /&gt;8         public function ArrayIterator(collection:Array) {&lt;br /&gt;9            _collection = collection;&lt;br /&gt;10            _index = _collection.length - 1;&lt;br /&gt;11         }&lt;br /&gt;12 &lt;br /&gt;13         public function hasNext():Boolean {&lt;br /&gt;14            return _index &amp;gt;    = 0;&lt;br /&gt;15         }&lt;br /&gt;16 &lt;br /&gt;17         public function next():Object {&lt;br /&gt;18            return _collection[_index--];&lt;br /&gt;19         }&lt;br /&gt;20 &lt;br /&gt;21         public function reset():void {&lt;br /&gt;22            _index = _collection.length - 1;&lt;br /&gt;23         }&lt;br /&gt;24 &lt;br /&gt;25      }&lt;br /&gt;26   }&lt;br /&gt;27 &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Por último definamos la interfaz común para nuestras colecciones, esta solo consta de un método que nos devolverá el tipo de iterador deseado.&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2      public interface ICollection {&lt;br /&gt;3         function iterator(type:String = null):IIterator;&lt;br /&gt;4      }&lt;br /&gt;5   }&lt;br /&gt;6 &lt;br /&gt;7 &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y la implementamos a nuestra existente colección StringColleciton:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2    &lt;br /&gt;3   public class StringCollection implements ICollection {&lt;br /&gt;4       &lt;br /&gt;5         private var _strings:Array;&lt;br /&gt;6 &lt;br /&gt;7         public function StringCollection() {&lt;br /&gt;8            _strings = new Array();&lt;br /&gt;9         }&lt;br /&gt;10 &lt;br /&gt;11         public function addElement(value:String):void {&lt;br /&gt;12            _strings.push(value);&lt;br /&gt;13         }&lt;br /&gt;14 &lt;br /&gt;15         public function iterator(type:String = null):IIterator {&lt;br /&gt;16           if(type == "ArrayReverseIterator") {&lt;br /&gt;17              return new ArrayReverseIterator(_strings);&lt;br /&gt;18           }else {&lt;br /&gt;19              new ArrayIterator(_strings);&lt;br /&gt;20           }&lt;br /&gt;21         }&lt;br /&gt;22      }&lt;br /&gt;23   }&lt;br /&gt;24 &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Genial !!!, ahora nuestro cliente solo sabe que nuestra clase solamente devuelve objetos que implementan la interfaz IIterator, ya no estamos exponiendo al cliente los detalles de implementación de la clase, él ya sabe que le devuelve un IIterator no importando si es un array, dictionary, etc…,  sabrá que cuenta con una interfaz común para navegar sobre la colección, y en un futuro podríamos agregar más tipos de iteradores para otro tipo de colecciones sin ningún problema.&lt;br /&gt;&lt;br /&gt;Ejemplo de uso en la parte del cliente:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   var collection:StringCollection = new StringCollection();&lt;br /&gt;2   collection.addElement("uno");&lt;br /&gt;3   collection.addElement("dos");&lt;br /&gt;4   collection.addElement("tres");&lt;br /&gt;5   collection.addElement("cuatro");&lt;br /&gt;6   var iterator:IIterator = collection.iterator();&lt;br /&gt;7   while(iterator.hasNext()) {&lt;br /&gt;8      trace(iterator.next());&lt;br /&gt;9   }&lt;br /&gt;10   iterator = collection.iterator("ArrayReverseIterator");&lt;br /&gt;11   while(iterator.hasNext()) {&lt;br /&gt;12      trace(iterator.next());&lt;br /&gt;13   }&lt;br /&gt;14 &lt;br /&gt;15    &lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A poco no está fregón ?, la colección nos puede devolver 2 tipos de iteradores dependiendo del tipo de parámetro que le pasemos al método iterator, cualquiera de las 2 implementaciones concretas implementa la misma interfaz por tanto el cliente no tendrá que cambiar su código del cómo itera sobre los elementos si más adelante decide implementar otro tipo de iterador.&lt;br /&gt;&lt;br /&gt;Aquí les dejo el diagrama de clases del ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__ZhsAyyhgGg/RwBZbCRdv1I/AAAAAAAAABE/x_TCtRJ1afQ/s1600-h/iterator.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/__ZhsAyyhgGg/RwBZbCRdv1I/AAAAAAAAABE/x_TCtRJ1afQ/s400/iterator.jpg" alt="" id="BLOGGER_PHOTO_ID_5116187497694347090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Cómo mejorarías el patrón compositive ó compuesto utilizando este patrón ?, bueno eso te toca a ti, ojala les haya quedado claro todo y cualquier comentario o sugerencia es bienvenida.&lt;br /&gt;&lt;br /&gt;Para el próximo post veremos probablemente otro patrón, es una sorpresilla.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Un saludote !&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-942739315884543009?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/942739315884543009/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=942739315884543009' title='2 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/942739315884543009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/942739315884543009'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2007/09/patrn-iterador-actionscript-30.html' title='Patrón Iterador – ActionScript 3.0'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__ZhsAyyhgGg/RwBZbCRdv1I/AAAAAAAAABE/x_TCtRJ1afQ/s72-c/iterator.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-1981880453238062226</id><published>2007-09-28T10:05:00.000-07:00</published><updated>2008-12-10T17:15:12.567-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Patrones de Diseño'/><title type='text'>Patrón Compuesto - ActionScript 3.0</title><content type='html'>&lt;span style="" lang="ES-MX"&gt;&lt;span style="font-weight: bold;"&gt;Patrón Compuesto&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Después de varios meses de inactividad en el blog xD (prometo no dejarlo abandonado de nuez), vamos a ver un tema muy interesante, el patrón compuesto implementado en ActionScript 3.0.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;      &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Este patrón tiene la finalidad de resolver la complejidad que podría resultar al hacer estructuras parecidas a la de un árbol de objetos, tanto la creación de estructuras complejas como la navegación sobre ellas se podrá hacer de forma sencilla implementándolo.&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Imaginémonos el árbol del tule (por si no lo saben está en Oaxaca, es el árbol más gordo del mundo hahahahaha), pues el tule está formado por ramas y hojas, por ejemplo las ramas pueden tener otras ramas y otras hojas y así sucesivamente. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Nuestra rama es una composición de uno o más objetos similares que tiene una funcionalidad similar y también tenemos a las hojas que son objetos únicos, no tienen otros objetos dentro de ellas como las ramas.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Un ejemplo:&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/__ZhsAyyhgGg/Rv01WSRdvyI/AAAAAAAAAAs/wfqy9ffjx3k/s1600-h/tule.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/__ZhsAyyhgGg/Rv01WSRdvyI/AAAAAAAAAAs/wfqy9ffjx3k/s320/tule.jpg" alt="" id="BLOGGER_PHOTO_ID_5115303408741236514" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;  &lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;La clave está en implementar la misma interfaz tanto para los objetos compuestos (ramas) como las hojas (objetos únicos), todo esto hace que programemos por interfaz sin importar que tipo de objetos estemos utilizando a nuestra clase gestora de ramas y hojas (Árbol del Tule) no le importa que tipo concreto le demos, a esta solo le importa que le demos instancias de clase que implementen la interfaz.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Veamos como haríamos nuestro diagrama implementando el patrón:&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__ZhsAyyhgGg/Rv01wCRdv0I/AAAAAAAAAA8/JCRJrelDD2M/s1600-h/diagramC.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/__ZhsAyyhgGg/Rv01wCRdv0I/AAAAAAAAAA8/JCRJrelDD2M/s400/diagramC.jpg" alt="" id="BLOGGER_PHOTO_ID_5115303851122868034" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;  &lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Como podemos ver tanto nuestras clases Hoja y Rama implementan la interfaz ITreeElement&lt;span style=""&gt;  &lt;/span&gt;y &lt;st1:personname productid="la Rama" st="on"&gt;la Rama&lt;/st1:personname&gt; a su vez puede contener más instancias de clase que implemente la interfaz ITreeElement. La clase Árbol es la que va a ser utilizada por el cliente para formar la estructura del Tule (si que le va a costar trabajo), agregando ramas o hojas.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Ahora si empecemos a codificar el diagrama, empecemos por la interfaz:&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;1   package {&lt;br /&gt;2   &lt;br /&gt;3       public interface ITreeElement {&lt;br /&gt;4           function addElement(element:ITreeElement):void;&lt;br /&gt;5           function removeElement(element:ITreeElement):Boolean;&lt;br /&gt;6           function getInfo():String;&lt;br /&gt;7       }&lt;br /&gt;8   }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Ahora las 2 clases concretas (Rama y Hoja) que implementarán la interfaz ITreeElement:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2   &lt;br /&gt;3       import mx.collections.ArrayCollection;&lt;br /&gt;4   &lt;br /&gt;5       public class Rama implements ITreeElement {&lt;br /&gt;6       &lt;br /&gt;7       &lt;br /&gt;8           private var _elementos:ArrayCollection;&lt;br /&gt;9       &lt;br /&gt;10       &lt;br /&gt;11           public function Rama() {&lt;br /&gt;12               _elementos = new ArrayCollection();&lt;br /&gt;13           }&lt;br /&gt;14       &lt;br /&gt;15           public function addElement(element:ITreeElement):void {&lt;br /&gt;16               _elementos.addItem(element);&lt;br /&gt;17           }&lt;br /&gt;18       &lt;br /&gt;19           public function removeElement(element:ITreeElement):Boolean {&lt;br /&gt;20               for(var i:Number = 0; i &amp;lt; _elementos.length; i++) {&lt;br /&gt;21                   if(_elementos.getItemAt(i) == element) {&lt;br /&gt;22                       _elementos.removeItemAt(i);&lt;br /&gt;23                       return true;&lt;br /&gt;24                   }&lt;br /&gt;25               }&lt;br /&gt;26               return false;&lt;br /&gt;27           }&lt;br /&gt;28       &lt;br /&gt;29           public function getInfo():String {&lt;br /&gt;30               var output:String = "\n--------------------------------------\n";&lt;br /&gt;31               output += "Soy una rama y tengo "+_elementos.length+" elemento(s) : ";&lt;br /&gt;32               for(var i:Number = 0; i &amp;lt; _elementos.length; i++) {&lt;br /&gt;33                   var elemento:ITreeElement = _elementos.getItemAt(i) as ITreeElement;&lt;br /&gt;34                   output += elemento.getInfo();&lt;br /&gt;35               }&lt;br /&gt;36               output += "\n--------------------------------------\n";&lt;br /&gt;37               return output;&lt;br /&gt;38           }&lt;br /&gt;39       }&lt;br /&gt;40   }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Como vemos la clase Rama tiene una propiedad que es una colección de elementos, esta es la que contendrá otras &lt;span style=""&gt; &lt;/span&gt;ramas ó hojas que se le vayan agregando.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Algo muy importante es que le pongas mucha atención al método getInfo, ve como iteramos sobre todos los elementos de la rama y delegamos la tarea de obtener la información de los elementos sin importarle sin son ramas o hojas.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Si nos ponemos a pensar un poquito cuando hagamos nuestra clase Hoja, esta tendrá métodos que no tienen ningún significado para esta como addElement y removeElement, ya que las hojas no pueden contener otros elementos. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;¿ Qué podemos hacer para solucionar este problema ?&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Una solución es poner los métodos sin ningún tipo de implementación o podemos que los métodos que no tienen ningún sentido para la hoja arrojen una excepción, optaremos por la segunda opción.&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2   &lt;br /&gt;3       public class Hoja implements ITreeElement {&lt;br /&gt;4       &lt;br /&gt;5           public function Hoja() {&lt;br /&gt;6           }&lt;br /&gt;7       &lt;br /&gt;8           function addElement(element:ITreeElement):void {&lt;br /&gt;9               throw new Error("Este método no es posible llamarlo desde una instancia Hoja");&lt;br /&gt;10           }&lt;br /&gt;11       &lt;br /&gt;12           function removeElement(element:ITreeElement):Boolean {&lt;br /&gt;13               throw new Error("Este método no es posible llamarlo desde una instancia Hoja");&lt;br /&gt;14           }&lt;br /&gt;15       &lt;br /&gt;16           function getInfo():String {&lt;br /&gt;17               return "Soy una hoja sana y fuerte.";&lt;br /&gt;18           }&lt;br /&gt;19       }&lt;br /&gt;20   }&lt;br /&gt;21&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;Ve como en la hoja solamente necesitamos retornar la cadena de información con getInfo, ya que es un elemento único.&lt;/p&gt;    &lt;p class="MsoNormal"&gt;Luego aquí va nuestra clase Árbol que el cliente usará para formar su arbolote:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2   &lt;br /&gt;3       import mx.collections.ArrayCollection;&lt;br /&gt;4   &lt;br /&gt;5       public class Arbol {&lt;br /&gt;6       &lt;br /&gt;7       &lt;br /&gt;8           private var _nombre:String;&lt;br /&gt;9           private var _peso:String;&lt;br /&gt;10           private var _diametro:String;&lt;br /&gt;11           private var _elementos:ArrayCollection;&lt;br /&gt;12       &lt;br /&gt;13       &lt;br /&gt;14           public function Arbol(nombre:String, peso:String, diametro:String) {&lt;br /&gt;15               _nombre = nombre;&lt;br /&gt;16               _peso = peso;&lt;br /&gt;17               _diametro = diametro;&lt;br /&gt;18               _elementos = new ArrayCollection();&lt;br /&gt;19           }&lt;br /&gt;20       &lt;br /&gt;21           public function get nombre():String {&lt;br /&gt;22               return _nombre;&lt;br /&gt;23           }&lt;br /&gt;24       &lt;br /&gt;25           public function get peso():String {&lt;br /&gt;26               return _peso;&lt;br /&gt;27           }&lt;br /&gt;28       &lt;br /&gt;29           public function get diametro():String {&lt;br /&gt;30               return _diametro;&lt;br /&gt;31           }&lt;br /&gt;32       &lt;br /&gt;33           public function agregarElemento(e:ITreeElement):void {&lt;br /&gt;34               _elementos.addItem(e);&lt;br /&gt;35           }&lt;br /&gt;36       &lt;br /&gt;37           public function obtenerEstructura():void {&lt;br /&gt;38               for(var i:Number = 0; i &amp;lt; _elementos.length; i++) {&lt;br /&gt;39                   var elemento:ITreeElement = _elementos.getItemAt(i) as ITreeElement;&lt;br /&gt;40                   trace(elemento.getInfo());&lt;br /&gt;41               }&lt;br /&gt;42           }&lt;br /&gt;43       &lt;br /&gt;44       }&lt;br /&gt;45   }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;Por último un ejemplo de cómo podríamos formar un árbol con ramas y hojas,&lt;span style=""&gt;  &lt;/span&gt;y al final obtener su estructura interna.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   var rama1:Rama = new Rama();&lt;br /&gt;2   rama1.addElement(new Hoja());&lt;br /&gt;3   rama1.addElement(new Hoja());&lt;br /&gt;4   rama1.addElement(new Hoja());&lt;br /&gt;5   var rama2:Rama = new Rama();&lt;br /&gt;6   rama2.addElement(new Hoja);&lt;br /&gt;7   rama1.addElement(rama2);&lt;br /&gt;8   var rama3:Rama = new Rama();&lt;br /&gt;9   rama3.addElement(new Rama());&lt;br /&gt;10   var hojaSola:Hoja = new Hoja();&lt;br /&gt;11               &lt;br /&gt;12   var arbol:Arbol = new Arbol("Árbol del Tule", "636 toneladas", "14.05 m");&lt;br /&gt;13   arbol.agregarElemento(rama1);&lt;br /&gt;14   arbol.agregarElemento(rama3);&lt;br /&gt;15   arbol.agregarElemento(hojaSola);&lt;br /&gt;16               &lt;br /&gt;17   arbol.obtenerEstructura();&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;Es un ejemplo que lo podemos mejorar utilizando el patrón &lt;a href="http://en.wikipedia.org/wiki/Iterator_pattern"&gt;Iterator&lt;/a&gt;, en mi siguiente post lo veremos en detalle.&lt;/p&gt;    &lt;p class="MsoNormal"&gt;Cualquier comentario ó sugerencia es bienvenida.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="font-weight: bold;"&gt;Un saludote !&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-1981880453238062226?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/1981880453238062226/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=1981880453238062226' title='29 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/1981880453238062226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/1981880453238062226'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2007/09/patrn-compuesto.html' title='Patrón Compuesto - ActionScript 3.0'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__ZhsAyyhgGg/Rv01WSRdvyI/AAAAAAAAAAs/wfqy9ffjx3k/s72-c/tule.jpg' height='72' width='72'/><thr:total>29</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2915850027029705420.post-2964186078158502152</id><published>2007-05-15T14:37:00.000-07:00</published><updated>2008-12-10T17:15:36.955-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Patrones de Diseño'/><title type='text'>Patrón Modelo Vista Controlador - ActionScript 3.0</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Trataré de explicar con lo poco que se, este patrón de diseño utilizando actionscript 3.0 para los amantes de este lenguaje como yo, me servirá a mi para aprender este mundo maravilloso de los patrones y también a todos los lectores que les interese el tema, así que comencemos. ;-)&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;      &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Las aplicaciones consisten de interfaces de usuario, lógica del negocio y modelos de datos, por ejemplo un componente “combobox” cuenta con elementos de la interfaz del usuario como áreas con scroll ó áreas clickeables, lógica que responde de acuerdo a los eventos generados por el usuario (el usuario de click en una opción del combobox) y modelos de datos (la información que reside en nuestro combobox).&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Comúnmente los programadores suelen combinar los 3 elementos en un solo objeto en lugar de crear diferentes objetos para cada responsabilidad, cuando la interfaz y los datos están unidos en un objeto genera los siguientes problemas:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;span style="" lang="ES-MX"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="" lang="ES-MX"&gt;Es difícil utilizar los datos de nuestro modelo por fuera de nuestro objeto, por ejemplo si tenemos un inputText y la información escrita en el tiene que ser enviada al servidor, esa información tendría que ser guardada en el mismo objeto y tendríamos que asignarle la responsabilidad de enviar ese dato al servidor, esto viola con los principios de &lt;a href="http://es.wikipedia.org/wiki/Grasp#Alta_cohesi.C3.B3n"&gt;Alta Cohesión&lt;/a&gt;. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;        &lt;ul&gt;&lt;li&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;/o:p&gt;No puedes cambiar la interfaz de usuario fácilmente utilizando el mismo modelo de datos, esto es porque el modelo de datos y la interfaz residen en un solo objeto (están fuertemente acoplados, viola el principio de &lt;a href="http://es.wikipedia.org/wiki/Grasp#Bajo_acoplamiento"&gt;Bajo Acoplamiento&lt;/a&gt;), el cambio de interfaz requeriría copiar todos los datos de la interfaz anterior a la nueva.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;ul&gt;&lt;li&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;Múltiples vistas simultaneas de los datos es muy difícil, por ejemplo, tu podrías querer desplegar 2 o más gráficas de los mismo datos y también actualizarlas al cambiar los datos, si tienes 2 gráficas donde los datos y la presentación están mezclados tendrías que actualizar los datos que residen en cada uno de los objetos.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;br /&gt;Ahora pasemos a explicar cada una de las partes que conforman el patrón:&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;span style="font-weight: bold;"&gt;El modelo&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;/o:p&gt;Es el elemento que almacena los datos, el modelo puede ser tan simple que solamente guarde un solo dato primitivo como un entero así como estructuras complejas de datos por ejemplo otros objetos. Veamos al modelo como un almacén de datos y una cosa muy importante el modelo debe ser “independiente” tanto de la vista y el controlador, esto quiere decir que el modelo no debe saber de la existencia del controlador y la vista, este último punto grábatelo como si fuera algo de vida o muerte xD, esto es debido a que se genera un bajo acoplamiento y te da la posibilidad de cambiar las vistas y controladores a tu antojo sin mover nada en nuestro modelo.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;        &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;span style="font-weight: bold;"&gt;La vista&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;/o:p&gt;Es todo lo visual, todo lo que ve el usuario, la vista utiliza los datos del modelo para dibujarse así mismo. La vista puede consistir de elementos como botones, imágenes, formularios, etc.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Como conclusión la vista solamente consiste de elementos visuales y la lógica necesaria para leer los datos del modelo para ser utilizados en la interfaz, como regla la vista no puede actualizar los datos del modelo.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;span style="font-weight: bold;"&gt;El controlador&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;          &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;/o:p&gt;El controlador es responsable de capturar los eventos generados por el usuario, y de esa manera actualizar el modelo y la vista. Por ejemplo si el modelo necesita actualizar los datos, el controlador es responsable de esa acción.&lt;span style=""&gt;  &lt;/span&gt;&lt;o:p&gt;&lt;br /&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Ahora si pasemos a codificar un ejemplo muy sencillo para que se entienda bien el concepto.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;        &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;/o:p&gt;Vamos a hacer una clase que va a ser nuestro modelo llamada DataModel, solo va a contener un miembro privado entero que ira incrementándose cada segundo y este se lo notificará a sus listeners. Para que la clase pueda disparar eventos necesitamos heredar de la clase “&lt;/span&gt;flash.events.EventDispatcher&lt;span style="" lang="ES-MX"&gt;”, y cuando cambie el estado de nuestro objeto que es cuando se cambia la propiedad number llamamos al método”&lt;/span&gt;dispatchEvent” y le pasamos como argumento un objeto del tipo Event, tu tienes la libertad de crear tus propios eventos heredando de la clase Event, la propiedad privada thread es como un hilo de java, al llamar al método start, se llamará al método onTimer cada segundo.&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package com.jahepi.domain.models {&lt;br /&gt;2   &lt;br /&gt;3       import flash.events.EventDispatcher;&lt;br /&gt;4       import flash.events.Event;&lt;br /&gt;5       import flash.utils.Timer;&lt;br /&gt;6       import flash.events.TimerEvent;&lt;br /&gt;7   &lt;br /&gt;8       public class DataModel extends EventDispatcher {&lt;br /&gt;9       &lt;br /&gt;10           private var _number:Number = 0;&lt;br /&gt;11           private var _thread:Timer;&lt;br /&gt;12       &lt;br /&gt;13           public function DataModel() {&lt;br /&gt;14               _thread = new Timer(1000);&lt;br /&gt;15               _thread.addEventListener(TimerEvent.TIMER, onTimer);&lt;br /&gt;16               _thread.start();&lt;br /&gt;17           }&lt;br /&gt;18       &lt;br /&gt;19           public function set number(number:Number):void {&lt;br /&gt;20               _number = number;&lt;br /&gt;21               dispatchEvent(new Event(Event.CHANGE));&lt;br /&gt;22           }&lt;br /&gt;23       &lt;br /&gt;24           public function get number():Number {&lt;br /&gt;25               return _number;&lt;br /&gt;26           }&lt;br /&gt;27       &lt;br /&gt;28           private function onTimer(event:TimerEvent):void {&lt;br /&gt;29               number++;&lt;br /&gt;30           }&lt;br /&gt;31       &lt;br /&gt;32       }&lt;br /&gt;33   }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Ahora pasemos a hacer 2 vistas (DataView1 y DataView2) estas heredan de la clase Sprite, y a cada una se la pasa la referencia del Modelo en su constructor, si te fijas en la línea de “&lt;/span&gt;_model.addEventListener(Event.CHANGE, onUpdate);”, registramos el listener para que nos avise cuando cambia el estado de nuestro modelo, y este llama al método “onUpdate”, para poder así hacer los cambios pertinentes en nuestra interfaz, cada vista es muy simple pero muestra a grandes rasgos como el modelo notifica a cada una de las vistas cuando su estado cambia y se ve reflejado en cada una de ellas al cambiar la propiedad number del modelo.&lt;br /&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;br /&gt;&lt;/o:p&gt;&lt;span style="font-weight: bold;"&gt;DataView1&lt;/span&gt;&lt;o:p&gt;&lt;br /&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package com.jahepi.domain.views {&lt;br /&gt;2   &lt;br /&gt;3   &lt;br /&gt;4       import flash.display.Sprite;&lt;br /&gt;5       import flash.text.TextField;&lt;br /&gt;6       import flash.events.Event;&lt;br /&gt;7       import com.jahepi.domain.models.DataModel;&lt;br /&gt;8       import flash.display.Shape;&lt;br /&gt;9&lt;br /&gt;10       public class DataView1 extends Sprite {&lt;br /&gt;11       &lt;br /&gt;12           private var _model:DataModel;&lt;br /&gt;13           private var _textField:TextField;&lt;br /&gt;14       &lt;br /&gt;15           public function DataView1(model:DataModel) {&lt;br /&gt;16               _model = model;&lt;br /&gt;17               _model.addEventListener(Event.CHANGE, onUpdate);&lt;br /&gt;18           &lt;br /&gt;19               var shape:Shape = new Shape();&lt;br /&gt;20               shape.graphics.beginFill(0xff0000, 1);&lt;br /&gt;21               shape.graphics.drawRect(0, 0, 35, 35);&lt;br /&gt;22               shape.graphics.endFill();&lt;br /&gt;23               var textField:TextField = new TextField();&lt;br /&gt;24               textField.text = "vista 1";&lt;br /&gt;25               textField.y = 16;&lt;br /&gt;26           &lt;br /&gt;27               _textField = new TextField();&lt;br /&gt;28           &lt;br /&gt;29               addChild(shape);&lt;br /&gt;30               addChild(_textField);&lt;br /&gt;31               addChild(textField);&lt;br /&gt;32           }&lt;br /&gt;33       &lt;br /&gt;34       &lt;br /&gt;35           private function onUpdate(event:Event):void {&lt;br /&gt;36               _textField.text = String(_model.number);&lt;br /&gt;37           }&lt;br /&gt;38       &lt;br /&gt;39       }&lt;br /&gt;40   }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;br /&gt;&lt;/o:p&gt;&lt;span style="font-weight: bold;"&gt;DataView2&lt;/span&gt;&lt;o:p&gt;&lt;br /&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package com.jahepi.domain.views {&lt;br /&gt;2   &lt;br /&gt;3       import flash.display.Sprite;&lt;br /&gt;4       import flash.text.TextField;&lt;br /&gt;5       import flash.events.Event;&lt;br /&gt;6       import com.jahepi.domain.models.DataModel;&lt;br /&gt;7       import flash.display.Shape;&lt;br /&gt;8   &lt;br /&gt;9       public class DataView2 extends Sprite {&lt;br /&gt;10       &lt;br /&gt;11           private var _model:DataModel;&lt;br /&gt;12           private var _textField:TextField;&lt;br /&gt;13       &lt;br /&gt;14           public function DataView2(model:DataModel) {&lt;br /&gt;15               _model = model;&lt;br /&gt;16               _model.addEventListener(Event.CHANGE, onUpdate);&lt;br /&gt;17           &lt;br /&gt;18               var shape:Shape = new Shape();&lt;br /&gt;19               shape.graphics.beginFill(0x00ff00, 1);&lt;br /&gt;20               shape.graphics.drawCircle(15, 20, 25);&lt;br /&gt;21               shape.graphics.endFill();&lt;br /&gt;22               var textField:TextField = new TextField();&lt;br /&gt;23               textField.text = "vista 2";&lt;br /&gt;24               textField.y = 16;&lt;br /&gt;25           &lt;br /&gt;26               _textField = new TextField();&lt;br /&gt;27               _textField.textColor = 0x0000ff;&lt;br /&gt;28           &lt;br /&gt;29               addChild(shape);&lt;br /&gt;30               addChild(_textField);&lt;br /&gt;31               addChild(textField);&lt;br /&gt;32           }&lt;br /&gt;33       &lt;br /&gt;34       &lt;br /&gt;35           private function onUpdate(event:Event):void {&lt;br /&gt;36               _textField.text = String(_model.number);&lt;br /&gt;37           }&lt;br /&gt;38       }&lt;br /&gt;39   }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Ahora le toca el turno de nuestro controlador, este tendrá el objetivo de cambiar las vistas cuando sea apretado un botón en la interfaz, el controlador cuenta con un array que registra todas las referencias de las vistas y también cuenta con la referencia del modelo en su propiedad model por si queremos mas adelante modificar el estado del modelo desde ahí.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package com.jahepi.domain.controllers {&lt;br /&gt;2       import com.jahepi.domain.models.DataModel;&lt;br /&gt;3       import flash.display.SimpleButton;&lt;br /&gt;4       import flash.display.Shape;&lt;br /&gt;5       import flash.events.MouseEvent;&lt;br /&gt;6       import flash.display.Sprite;&lt;br /&gt;7   &lt;br /&gt;8       public class DataController extends Sprite {&lt;br /&gt;9       &lt;br /&gt;10           private var _views:Array;&lt;br /&gt;11           private var _model:DataModel;&lt;br /&gt;12           private var _index:Number = 0;&lt;br /&gt;13       &lt;br /&gt;14           public function DataController(model:DataModel) {&lt;br /&gt;15               _views = new Array();&lt;br /&gt;16               _model = model;&lt;br /&gt;17           &lt;br /&gt;18               var shape:Shape = new Shape();&lt;br /&gt;19               shape.graphics.beginFill(0xffff00, 1);&lt;br /&gt;20               shape.graphics.drawRect(0,0,30,30);&lt;br /&gt;21               shape.graphics.endFill();&lt;br /&gt;22               var button:SimpleButton = new SimpleButton(shape, shape, shape, shape);&lt;br /&gt;23               button.addEventListener(MouseEvent.CLICK, changeView);&lt;br /&gt;24               button.y = 100;&lt;br /&gt;25               addChild(button);&lt;br /&gt;26           }&lt;br /&gt;27       &lt;br /&gt;28           public function addView(view:Sprite):void {&lt;br /&gt;29               _views.push(view);&lt;br /&gt;30           }&lt;br /&gt;31       &lt;br /&gt;32           private function changeView(event:MouseEvent):void {&lt;br /&gt;33               if((_index-1) != -1) {&lt;br /&gt;34                  removeChild(_views[_index-1]);&lt;br /&gt;35               }&lt;br /&gt;36               if(_index &amp;gt;= _views.length) {&lt;br /&gt;37                   _index = 0;&lt;br /&gt;38               }&lt;br /&gt;39               addChild(_views[_index++]);&lt;br /&gt;40           }&lt;br /&gt;41       }&lt;br /&gt;42   }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Y ahora la aplicación final, el punto de entrada donde se crean las instancias:&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;1   package {&lt;br /&gt;2   &lt;br /&gt;3       import flash.display.Sprite;&lt;br /&gt;4       import com.jahepi.domain.views.*;&lt;br /&gt;5       import com.jahepi.domain.models.DataModel;&lt;br /&gt;6       import com.jahepi.domain.controllers.DataController;&lt;br /&gt;7&lt;br /&gt;8       public class MVC extends Sprite {&lt;br /&gt;9       &lt;br /&gt;10           public function MVC() {&lt;br /&gt;11           &lt;br /&gt;12               var model:DataModel = new DataModel();&lt;br /&gt;13               var controller:DataController = new DataController(model);&lt;br /&gt;14               var view1:DataView1 = new DataView1(model);&lt;br /&gt;15               var view2:DataView2 = new DataView2(model);&lt;br /&gt;16               controller.addView(view1);&lt;br /&gt;17               controller.addView(view2);&lt;br /&gt;18               addChild(controller);&lt;br /&gt;19           &lt;br /&gt;20           }&lt;br /&gt;21       }&lt;br /&gt;22   }&lt;br /&gt;23&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;Unan todo en un proyecto de AS3.0, y verán un pequeño cuadro que es el botón, cuando le dan click se genera la primera vista y cada vez que se cambia el estado del modelo se le notifica a la vista actual cambiado el valor numérico que despliega y si le vuelves a dar click al botón cambia a la segunda vista conservando la secuencia númerica obtenida del modelo. Eso es todo, ojalá no queden dudas ó si me equivoqué en algo no duden en comentar mis horrores.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="" lang="ES-MX"&gt;&lt;span style="font-weight: bold;"&gt;Un saludote !&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2915850027029705420-2964186078158502152?l=jahepi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jahepi.blogspot.com/feeds/2964186078158502152/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2915850027029705420&amp;postID=2964186078158502152' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/2964186078158502152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2915850027029705420/posts/default/2964186078158502152'/><link rel='alternate' type='text/html' href='http://jahepi.blogspot.com/2007/05/mvc-pattern-patrn-modelo-vista.html' title='Patrón Modelo Vista Controlador - ActionScript 3.0'/><author><name>jahepi</name><uri>http://www.blogger.com/profile/00415760882253431678</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
