Caso de estudio: Flex store simplificado

En la fase de diseño estructural de un desarrollo Flex se deben tener en cuenta varios factores como la organización, intercomunicación y división lógica de las vistas.
Este caso de estudio está enfocado a desarrolladores Flex noveles que quieran conocer una forma de plantear sus arquitecturas de manera modular.

Organización y división lógica de las vistas

Una aplicación Flex suele estar compuesta por varias vistas, cada una de ellas, a su vez, puede estar formada por otras sub-vistas anidadas. Es una buena práctica separar dichas vistas en componentes lo suficientemente pequeños (y lo suficientemente grandes) como para que describan una funcionalidad concreta.
Las diferentes vistas de una aplicación se deben separar en unidades de funcionalidad (con significado), de este modo la estructura será más legible, será más sencillo detectar posibles errores y potenciaremos la reutilización.

Intercomunicación vistas-aplicación

Nuestra aplicación Flex en todo momento dispone de un estado (modelo). Dicho estado queda definido por el contenido de las variables que alimentan a los componentes: dataProviders, selectedItems, etc… La manera recomendada de enlazar el modelo de la aplicación con su representación gráfica (vista) es a través de data binding. Para ello mantendremos el modelo de datos centralizado en un lugar y enlazaremos a él todas las vistas mediante data binding.
Si queremos acabar de aislar nuestras vistas deberemos tener el cuidado de dejar abierto un canal a través del cual la aplicación pudea ser notificada de acciones y no delegar directamente a la vista esta tarea. Conseguiremos esto haciendo que nuestras vistas lancen eventos. Preferiblemente eventos personalizados con un significado acorde con la acción que lo lanzó. Por ejemplo, al cambiar la seleccion en un listado de productos podríamos lanzar un evento “seleccionDeProducto”.
Es interesante también centralizar el lugar donde se van a recibir dichos eventos. Para ello crearemos una clase (Controlador) que se ocupará exclusivamente de escuchar todos los eventos de la aplicación y ejecutar las acciones que sean pertinentes.

Así pues, resumiendo, por un lado tendremos que enlazar nuestras vistas al modelo de datos y por otro, si la vista permite interacción, ésta dispondrá de un mecanismo de notificación de eventos para que el controlador de la aplicación pueda registrarse a ellos.

Un posible flujo a seguir:

  1. Crear la estructura del proyecto
  2. Detectar las vistas principales.
  3. Crear el modelo de datos.
  4. Desglosar cada vista principal en sub-vistas.
  5. Definir los eventos y crear el controlador.

Vamos a tomar como ejemplo una tienda virtual tipo el Flex Store de Adobe (muy simplificado).

1. Crear la estructura del proyecto

En este proyecto vamos a definir la siguiente estructura de carpetas:
Estructura de carpetas

  • control: aquí guardaremos el archivo correspondiente a nuestra clase Controlador, que se ocupará de escuchar los eventos que las vistas lancen y llevará a cabo las acciones que sean necesarias.
  • event: en esta carpeta guardaremos todos los eventos personalizados que tengamos que crear.
  • model: aquí guardaremos la clase de nuestro modelo de datos y todas las clases que pudean estar relacionadas.
  • view: la carpeta view es donde debemos guardar todos los archivos .mxml (y .as de soporte) que representen las diferentes vistas y sub-vistas en la aplicación.
  • vo: Los VOs (Value Object) son pequeñas clases sin lógica (solo propiedades) que representan entidades en la aplicación. En la carpeta vo guardaremos todos los Value Objects que sean necesarios.

2. Detectar las vistas principales

La aplicación empieza en una vista con un listado de productos, una zona para ver el detalle del producto y una zona para almacenar el pedido, cuando acabamos el pedido vamos a otra vista donde se nos pide la información de pago y desde donde se puede enviar el pedido.
Todo esto suma 2 vistas principales: La vista de creación del pedido y la vista de proceso del pedido.

3. Crear el modelo de datos.

Simplificando mucho, el modelo de datos de una aplicación de e-commerce podría estar compuesto por: productos, productoSeleccionado y productosAdquiridos y totalPedido.
ModeloDeDatos.as
[ftf w=”500″ h=”200″]
package model
{
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
import vo.ProductoVO;

public class ModeloDeDatos
{
private static var instancia:ModeloDeDatos;
public static function getInstance():ModeloDeDatos
{
if( instancia==null ) instancia = new ModeloDeDatos();
return instancia;
}

[Bindable] public var productos:ArrayCollection;
[Bindable] public var productoSeleccionado:ProductoVO;
[Bindable] public var productosAdquiridos:ArrayCollection;
[Bindable] public var totalPedido:Number;
[Bindable] public var vistaMainSelectedindex:int;
[Bindable] public var vistaProcesarPedidoSelectedindex:int;

public function ModeloDeDatos()
{
productos = new ArrayCollection();
productosAdquiridos = new ArrayCollection();
totalPedido = 0;
vistaMainSelectedindex = 0;
vistaProcesarPedidoSelectedindex = 0;
productosAdquiridos.addEventListener ( CollectionEvent.COLLECTION_CHANGE, productosAdquiridosCollectionChange );
}

private function productosAdquiridosCollectionChange( event:CollectionEvent ):void
{
var total:Number = 0;
for( var i:uint=0; i4. Desglosar cada vista principal en sub-vistas

En este momento ya podemos diferenciar tres archivos para las vistas: La vista de creación del pedido CreacionPedido.mxml, la vista donde se procesa la petición del pedido ProcesarPedido.mxml y el archivo principal donde se cargaran todas las vistas de la aplicación Main.mxml.
La vista CreacionPedido.mxml se puede desglosar en tres sub-vistas: El selector de productos SelectorProductos.mxml, el detalle del producto DetalleProducto.mxml y el panel del pedido acumulado PedidoAcumulado.mxml.
La vista ProcesarPedido.mxml se puede desglosar en tres sub-vistas: El formulario de envío de datos de pago FormEnvioDatos.mxml, la pantalla de envío satisfactorio EnvioSatisfactorio.mxml y la pantalla de envío erróneo EnvioErroneo.mxml.
Ésta es la estructura de vistas final en el proyecto de Flex Builder:
Estructura de vistas

Éste es el código de los archivos principales:
Main.mxml
[ftf w=”500″ h=”200″]







[/ftf]
CreacionPedido.mxml
[ftf w=”500″ h=”200″]










[/ftf]
ProcesarPedido.mxml
[ftf w=”500″ h=”200″]




[/ftf]

Como se puede ver, una de las ventajas de trabajar con mxml es que se pueden incluir las sub-vistas como componentes, de manera que las podemos separar en diferentes archivos obteniendo así una organización mucho más intuitiva y legible.

5. Definir los eventos y crear el controlador.

Una vez tenemos las vistas y sub-vistas creadas nos es fácil intuir como éstas se van a comunicar con la aplicación. Es decir, qué eventos van a lanzar.
El proceso es el siguiente: una vista lanza un evento, el controlador lo capta, éste llama al método que tenga definido como handler, que ejecuta una serie de acciones que modifican el modelo de datos y, como las vistas están enlazadas mediante data binding, éstas se actualizan automáticamente.
Para entender mejor esta colaboración revisaremos el código de una vista y una parte del controlador.
SelectorProductos.mxml
[ftf w=”500″ h=”200″]











[/ftf]
Controlador.as (parcial)
[ftf w=”500″ h=”200″]
package control
{
import flash.events.EventDispatcher;
import event.LineaDePedidoEvent;
import model.ModeloDeDatos;
import model.LineaDePedido;
import event.ProductoEvent;
import vo.ProductoVO;

public class Controlador extends EventDispatcher
{
private static var instancia:Controlador;
public static function getInstance():Controlador
{
if( instancia==null ) instancia = new Controlador();
return instancia;
}

public function Controlador()
{
inicializaListeners();
}
private function inicializaListeners():void
{
addEventListener( LineaDePedidoEvent.BORRAR_LINEA_DE_PEDIDO, borrarLineaDePedido );
addEventListener( LineaDePedidoEvent.AGREAGR_LINEA_DE_PEDIDO, agregarLineaDePedido );
addEventListener( ProductoEvent.PIDE_PRODUCTOS, pideProductos );
addEventListener( ProductoEvent.PRODUCTO_SELECCIONADO, productoSeleccionado );
}

// ….
// ….

private function productoSeleccionado( evt:ProductoEvent ):void
{
ModeloDeDatos.getInstance().productoSeleccionado = evt.producto;
}
}
}
[/ftf]
En SelectorProductos.mxml podemos ver que el DataGrid selectorProductos tiene un evento change definido que a su vez lanza un evento ProductoEvent.PRODUCTO_SELECCIONADO del controlador pasando como parámetro el producto que se ha seleccionado.
En Controlador.as vemos que estamos escuchando al evento que nos interesa ProductoEvent.PRODUCTO_SELECCIONADO y que cuando éste se ejecuta llama a un método productoSeleccionado que actualiza el modelo. El resultado final es que el mecanismo de data binding actualizará todas las vistas que estén registradas a la propiedad del modelo que se modificó, en este caso productoSeleccionado, que hará que la vista DetalleProducto.mxml muestre el detalle del producto seleccionado.
Este mismo flujo se aplica en el resto de vistas.
Si nuestra aplicación acaba teniendo muchas vistas y eventos o simplemente necesitamos agregar/quitar funcionalidades veremos que esta arquitectura nos facilita mucho la tarea.

44 Comentarios

  1. alek

    La cantidad de información inconexa y chapuza que he tenido que procesar desde hace mucho tiempo es intolerable.Este ejemplo es maravilloso , creo que madeinflex está a una altura donde es dificil encontral rival. Por el amor de Dios, si hubiera visto esta explicación antes…cuantas calamidades me hubiera ahorrado.
    Un saludo y gracias

  2. kique

    Necesitaba un tuto como este para poder empezar. Muchas gracias. Pero me surge una duda: Aqui se refleja el databinding en una direccion, ¿como se haria el databinding en las dos direcciones?

  3. Joan Garnet

    En realidad el único que debe poder modificar al modelo de datos es el controlador. Es decir, el databinding en principio no tiene porque ser en dos sentidos.
    La vista se debe comunicar con el modelo a través del controlador mediante eventos, nunca directamente.
    De todos modos te derivo a un post que se publicó aquí acerca de databinding en dos direcciones: Two way DataBinding.
    saludos!

  4. Pingback: MadeInFlex » Blog Archive » Caso de estudio: Flex store simplificado version Cairngorm

  5. Pingback: MadeInFlex » Blog Archive » Caso de estudio: FlexStore con Guasax

  6. Pingback: Comparativa de aplicaciones en Flex « think different, think flex

  7. Pingback: Flex+Cairngorm en castellano desde MIF » Joan | Garnet Flex:Flash:PHP:MySQL:JS

  8. jam

    Felicidades.
    Muy bien explicado.
    Tengo una duda de novato.
    Los datos del formulario los he localizado en
    Controlador.as ¿es correcto? ¿cómo se introducen ahí? ¿con bases de datos como sería?
    Cuando se pasa a pedido, donde se alojan estos datos?, porque ahí les pierdo la pista.
    Lo que estaría + que genial, es añadir un pequeñísimo ejemplo con base de datos.
    Gracias.

  9. Joan Garnet

    Los datos están todos en la clase ModeloDeDatos, el controlador modifica los valores a través de los eventos.
    Para ver un ejemplo de como sería con bases de datos puedes ver el ejemplo de Cairngorm y AMFPHP. No hay llamada a bases de datos pero si verás como enviar/recibir datos desde un servidor. El implementar la petición es una cuestión trivial en realidad, la complejidad está en como enviar / recibir.
    Saludos!

  10. Jam

    Los datos en ModeloDeDatos.as no aparecen, creo. Yo por lo menos no los veo (piensa que somos principiantes) y por otro lado si me recomiendas un ejemplo de bases de datos SIN bases de datos…., te lo agradezco pero no es didáctico.
    Saludos.

  11. Joan Garnet

    Si abres ModeloDeDatos.as verás que hay varias variables: productos, productoSeleccionado, etc… ésas son las variables que contienen los datos de los que toda la aplicación se alimenta. Ésa es una de las claves en el ejemplo, mantener todos los datos en un mismo lugar para no tener que buscarlos en lugares recónditos.

    En cuanto al ejemplo con bases de datos he encontrado algo aquí, espero que te sea de utilidad.
    Saludos

  12. Jam

    Hola Joan,
    Probé el link que me recomendaste. Entre el sistema WebOrb y el tutorial flexorb, hay un momento que uno se pierde y no hubo forma de hacerlo funcionar.

    Aunque no viene al caso, si me lo permitís, os pongo un link (no conozco para nada al que lo ha hecho) de lo que debería de ser un tutorial. Estoy convencido que con este método no se emplea más tiempo (al contrario), simplemente se tiene una idea clara de lo que se enseña, todo un arte. En este caso :
    Instalación de WAMP en Windows XP

    http://nix.upc.es/tfc/wiki/index.php/Instalaci%C3%B3n_de_WAMP_en_Windows_XP

  13. Alejandro

    Hola, muy bueno el ejemplo, si alguien puede sumar a al ejemplo acceso a datos con Flourine + .Net seria excelente.
    gracias

  14. SGS

    Que tal,

    No me queda claro la diferencia entre los archivos de modelo, controlador y evento…

    Alguien podría ampiarme algo más la información.

  15. Joan Garnet

    El modelo guarda el estado (las propiedades) de la aplicación y en principio no debe tener ninguna lógica (métodos) definida, el controlador se ocupa de recibir notificaciones (eventos) para realizar acciones que pueden o no modificar el modelo, finalmente los eventos encapsulan toda la información necesaria para que el controlador pueda ejecutar una acción determinada.
    Esto es muy por encima lo que pides. Si quieres profundizar más te recomiendo que leas algún artículo acerca de arquitecturas MVC. En google encontraras un montón de referencias e incluso realizadas en AS3.
    Saludos!

  16. demian

    buenas! como se hace para una ves hecho el pedido se envie a un mail (al mio seria) con toda la informacion???

  17. Willy

    Con esto de los eventos tengo una duda.

    Creo un pop-up con esta función:

    public function popUp() : void {
    var createdPopUp:alta_clientes = new alta_clientes();
    PopUpManager.addPopUp(createdPopUp, DisplayObject( mx.core.Application.application ), true);
    PopUpManager.centerPopUp( createdPopUp );
    creeatedPopUp.alta_de_clientes.addEventListener(CloseEvent.CLOSE,refrescar2,false,0,true);
    }

    Cuando pulso el botón de cerrar del componente Panel, refrescar el contenido del documento desde el q abro, sin embargo cuando pulso el boton aceptar ( y actualiza correctamente los datos del cliente), no hay forma de que ejecute la función de refresco.
    He probado con :
    public function cerrarPopUp() : void {
    try {
    this.dispatchEvent(new CloseEvent(CloseEvent.CLOSE));
    Alert.show('sí');
    } catch(e:ErrorEvent)
    {
    Alert.show(e.text);
    }

    PopUpManager.removePopUp(this);
    }

    E incluso cree mi própio evento ( y gracias a vosotros) por el mismo método, pero nada… no refresca, gracias de antemano y disculpar las molestias.

  18. Pablo

    Hola joan! gracias por este ejemplo, creo que la leccion de como se organiza un proyecto es una de las cosas de las que se olvidaron en el TotalTraining for Flex 1 (Curso que recomiendo a todos antes de cacharrear con el MVC).

    Cuando 1 cosa se estudia surgen dudas, aqui va una:

    -¿En caso de utilizar un HTTPService para obtener los datos de este ejemplo (Por ejemplo de un archivo XML), donde lo colocarías?

    (En la aplicacion que estoy desarrollando utilizo muchos HTTPService y al final acaban desperdigados, nose si debo ponerlos en las vistas principales, en las subvistas o en los propios componentes. Lo que si que me ha quedado claro es que ay que pasar todos los datos al modelo y que el controlador trabaje con ellos)

  19. Joris Van Spilberguen

    Pablo pon los HTTPServices en el serviceLocator, leete la saga de articulos de cairngorm que hay aca en madeInFlex y busca el de ServiceLocator..

  20. Edward

    Increíble ejemplo para poder comenzar como dijeron anteriormente, no tienen idea de como ha hecho mi día mas feliz… sólo tengo una duda, donde recojo los datos para poder enviarlos por httpservice a un php??

  21. dani

    Genial Joan! Muchas gracias!
    Para alguien que esta empezando a empaparse del tema, este post es realmente…inspirador. Buenisima filosofia de trabajo. Clara y funcional. Muy bien explicado, también.
    Un saludo!

    Dani

  22. Pingback: Flex+Cairngorm en castellano desde MIF : Joan Garnet

  23. kamui

    una consulta yo tengo mi base de datos de mi tabla producto con estos campos (id_producto,imagenes,nombre y entre otros campos)

    y me gustaria como hacerlo con htppservices o amfphp

    como podria mostrar la imagen de mi producto desde la base de datos a flex

  24. Juarmos

    hola sr garnet
    podria ayudarme con lo ste:
    quiero realizar proyuecto de flex que guarde datos en un servidor de SQL de la misma forma facil como lo hace con mysql pero he intentado de todo y no lo he logrado. intente creando un archivo de conexion SQL y no he logrado que se conecte con el servidor de SQL. he logrado q se conecte con SQL2000 mas no con SQLExpress2005. de antemano miles y miles de gracias

  25. kamui

    te doy un consejo: crea tu base de datos normal mente
    y en .net conviertes los campos de la base de datos en xml luego haces la llamada en hhtpservices

  26. Juarmos

    eso es precisamente lo q no quiero hacer. neceisto tener conexion igual de facil como lo hago con SQL 2000… de todas maneras muchas Gracias.

  27. kamui

    parece q no me entendiste yo tambien trabajo con base de datos y uso httpservices, para comunicar la base de datos uso un codigo q me transforma los campos en xml que hacen comunicarse flex

  28. Juarmos

    disculpa, creo q no me supe explicar, la cuestion es q no nesecito trabajar con xlm ni con httpservices, ya trabaja sin ellos directamente con SQL2000 y quiero trabajar sin xml y sin httpservice en SQL2005

  29. oscarlosan

    Hola a todos, excelente tutorial y muy bien explicado. Mejor que cualquier libro.

    Una preguntita estoy utilizando Flex 3, hay algo que deba tener en cuenta o que se haga de otra forma en Flex 3?
    Es decir alguna funcionalidad o metodo de Flex 3 nuevo que sustituya al de Flex 2.

    Gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acerca de Made In Flex

Made In Flex es una comunidad de desarrolladores de Apache Flex creada en 2006.

Apache Flex, anteriormente conocido como Adobe Flex, es un SDK (kit de desarrollo de software) para crear aplicaciones enriquecidas - multiplataforma basadas en Adobe Flash donado por Adobe a la fundación Apache in 2011 y promocionado a proyecto de primer nivel en Diciembre de 2012.

Actualmente estamos cambiando muchos aspectos del sitio web para ofrecer un sitio útil para toda la comunidad que tenga en cuenta las necesidades actuales.

Últimas Fotos

Instalador de Apache Flex

Entrar o Registrase