Comunidad de diseño web y desarrollo en internet online

Duda con POO

Citar            
MensajeEscrito el 21 Abr 2013 06:01 pm
Estoy haciendo un programa en AS3/AIR con Flash, son varios formularios, uno en cada frame, con pequeñas diferencias entre ellos (según lo que se haga se salta de uno a otro).

Naturalmente no estoy usando POO porque para unos simples formularios me parecía más sencillo programar estilo "as2", pero claro... he empezado a añadir historias y cosas que se me ocurren mientras hago el desarrollo y claro, la cosa se complica.

Me pregunto si sería más sencillo hacerlo en POO, pero es que para un formulario no "veo" la POO.
Quiero decir, habría que hacer un objetos de todo y me parece que la cosa se complicaría mucho ¿o no?

¿Tenéis algún link a mano de algún tuto de formulario con POO?
Lo único que encuentro son juegos y no lo veo claro.

Gracias :wink:

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 22 Abr 2013 09:49 am
Varios formularios, con pequeñas diferencias entre ellos, y no ves POO?
Pues prácticamente para eso se inventó la herencia.
Crea una clase base que contenga los elementos comunes de los formularios, y después crea una subclase por cada formulario que extienda a esa clase, y que añada únicamente aquellos elementos que sean específicos de esa clase.

Por isidoro

Claber

498 de clabLevel

2 tutoriales

Genero:Masculino  

firefox
Citar            
MensajeEscrito el 23 Abr 2013 01:26 am
Gracias por contestar isidoro. La cuestión es que no se muy bien como "organizar las clases". Estoy un poco "verde". A ver si me puedes ayudar.

Simplificando mi aplicación, supongamos que queremos hacer una app simplemente con 1 formulario. Se trata de dar altas a clientes (para dar de alta un cliente se pide nombre, apellidos, direccion, telefono, etc).

La pantalla aparecen:
* Distintos campos de texto (unos tienen una long máxima, otros restricciones en los caracteres, unos fondo rojo y otros fondo gris). Es el formulario propiamente dicho.
* 1 Fondo de pantalla (la idea es tener un fondo por formulario, así se diferencian mejor).
* Unos "listados especiales". Son comunes a todos los formularios, uno en la parte superior y otro en el lateral de la derecha (son listados de clientes ya dados de altas en el sistema, según un criterio que ahora no viene al caso).
* Un campo de "estado" en la parte inferior, donde informo al user de lo que va ocurriendo en el programa (bbdd cargada, formulario cargado, formulario salvado con éxito,etc) y además informo de errores.
Por otro lado tengo 3 iconos: El icono INICIO (típica casa que lleva al programa al estado inicial), un icono que lleva a una pantalla especial con 1 solo campo de texto (sirve para dejar notas rápidas) y finalmente un icono CONFIGURACION (donde el usuario puede configurar ciertas cosas del programa).

Como digo, no tengo claro como hacer la POO.

Primero tendré una clase Main y de ahí colgarán las demás.

Tengo claro que necesito 1 clase por formulario. Otra clase para la pantalla de configuracion.
Luego me hace falta 1 clase para el listado superior y otra clase para el listado lateral.
Además necesitaré 1 clase para la barra de estado, ésta barra es común a toda la app (sale siempre incluso en la pantalla de config)
¿Es correcto de esta forma?

Los iconos, que son comunes en todas las pantallas, no se si tienen que crearse en Main o tengo que crear una clase por icono ¿¿??

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 23 Abr 2013 09:29 am
Bueno, realmente hay muchas formas de hacer esto dependiendo de tus necesidades, pero por lo que he leído podrías hacerlo de esta forma:

Clases necesarias:

Código ActionScript :

public class StatusBar
  dbName
  userForm
  ...

public class MenuBar //Mejor crear una clase que gestione los iconos y su comportamiento
  iconoCerrar
  ...

public class ListadoEspecialSuperior
  datosCliente1
  ...

public class ListadoEspecialDerecho
  otrosDatosCliente1
  ...

//Si los formularios tienen varios campos en común, crea una clase base:

public class AbstractForm
  public var name:String;
  public var address:String;
  ...

//Y cada formulario extenderá a esa clase base añadiendo sus propiedades específicas:

public class UserFormA extends AbstractForm
  public var variablePropiaDeA:int;
  public var otraVariablePropiaDeA:int;
  ...

public class UserFormB extends AbstractForm
  public var variablePropiaDeB:int;
  public var otraVariablePropiaDeB:int;
  ...

Para el contenedor del formulario, puedes crear una clase diferente para cada uno, aunque también podrías usar sólo 1 clase y pasarle como parámetros UserForm y backgroundColor, como prefieras:

Código ActionScript :

public class AbstractFormWindow //Será la clase base de todos los formularios
{
  public var userForm:AbstractForm; //En realidad sería mejor hacerla private, y acceder a ella con un getter, pero bueno
  private var backgroundColor:int;

  //Si van a ser comunes a todos los formularios es mejor que sean static const:
  private static const listadoEspecialSuperior:ListadoEspecialSuperior;
  private static const listadoEspecialDerecho:ListadoEspecialDerecho;
}

public class FormWindowA extends AbstractFormWindow
{
  public function FormWindowA()
  {
    userForm = new UserFormA();
    backgroundColor = 0x333333;
  }
}

public class FormWindowB extends AbstractFormWindow
{
  public function FormWindowB()
  {
    userForm = new UserFormB();
    backgroundColor = 0xff0000;
  }
}

Y finalmente creas la clase Main.
Por lo que leo, hay ciertas cosas que no van a pertenecer al formulario en sí, sino que van a ser comunes a la aplicación, como la barra de estado y el menú con los 3 iconos?
Si es así, esas clases irán dentro de Main, no dentro de la clase de la ventana de formulario.

Código ActionScript :

public class Main //Punto de entrada de la aplicación
{
  private static const statusBar:StatusBar; //Barra que indicará el estado de la aplicación
  private static const menuBar:MenuBar; //Menú con los 3 iconos

  private var formWindow:AbstractFormWindow;

  public function Main()
  {
    formWindow = new FormWindowA();
    //formWindow = new FormWindowB();
  }
}

Por isidoro

Claber

498 de clabLevel

2 tutoriales

Genero:Masculino  

firefox
Citar            
MensajeEscrito el 23 Abr 2013 01:19 pm
Muchísimas gracias isidoro.
Ayer estuve creando clases a ciegas para ver más/menos como funcionaban, hace muchísimos que no programo POO (desde mis clases de C++ en la universidad) y lo que en C++ me parecía muy intuitivo aquí me parece raro, acostumbrado como estoy al way-of-life-AS2

Voy a mirarme todo lo que has puesto. Me va a ayudar mucho.

Tan solo una duda más, lo que yo hago en mi app sin POO es cargar los datos con una consulta sql usando una variable global (por eso uso AIR) y luego usar la referencia en todas las partes del programa. También cargo los datos en varios arrays (que son variable globales también).

Usando el esquema que me has dado, entiendo que haría la consulta a la bbdd en StatusBar.
Después, desde dentro de otra clase, ¿la forma de acceder a esa variable desde otra clase sería algo así? --> desde la clase FormWindowA:

"StatusBar.FormWindowA .vble_clase_padre"

Imagino que para tener los datos disponibles de los arrays, habría que crear una clase "de datos" a la que todos puedan acceder para leer/escribir ¿no?

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 23 Abr 2013 02:28 pm
La forma más sencilla de usar variables globales es usar una clase que almacene un registro de esas variables.
Aunque en realidad desde el punto de vista de la OOP no es que esté bien hecho, y cada clase debería proporcionar métodos para acceder a sus datos, pero bueno, esto vale para cualquier situación y seguro que así te resulta más fácil.

Código ActionScript :

package
{
   public class Registry
   {
      public static var variableGlobal1:String;
      public static var variableGlobal2:int;
      ...
   }
}

Y después puedes acceder a ellas desde cualquier parte de la aplicación así:

Código ActionScript :

Registry.variableGlobal1;
Registry.variableGlobal2;


En cuanto a lo de hacer las consultas desde StatusBar, pues es mejor que crees una clase DatabaseManager que gestione todas las consultas a la db, y después accedes a ellas desde StatusBar y desde el resto de clases que las necesiten.

Por isidoro

Claber

498 de clabLevel

2 tutoriales

Genero:Masculino  

firefox
Citar            
MensajeEscrito el 23 Abr 2013 02:40 pm

isidoro escribió:

La forma más sencilla de usar variables globales es usar una clase que almacene un registro de esas variables.
Aunque en realidad desde el punto de vista de la OOP no es que esté bien hecho, y cada clase debería proporcionar métodos para acceder a sus datos, pero bueno, esto vale para cualquier situación y seguro que así te resulta más fácil.

Código ActionScript :

package
{
   public class Registry
   {
      public static var variableGlobal1:String;
      public static var variableGlobal2:int;
      ...
   }
}

Y después puedes acceder a ellas desde cualquier parte de la aplicación así:

Código ActionScript :

Registry.variableGlobal1;
Registry.variableGlobal2;


En cuanto a lo de hacer las consultas desde StatusBar, pues es mejor que crees una clase DatabaseManager que gestione todas las consultas a la db, y después accedes a ellas desde StatusBar y desde el resto de clases que las necesiten.


Gracias crack!!

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 25 Abr 2013 07:41 pm
Hola de nuevo. He empezado desde cero.
He creado 2 instancias desde el main(), una para el registro y otra para el databaseManager.
Otra más para escribir cosas en pantalla.

En el databaseManager he creado un método que lee la BBDD (usando SQLlite) y luego escribe los datos en las variables del registro, pero claro, en principio desde una clase no puedo acceder a los datos de otra.

Así que he hecho lo siguiente:

MAIN():

Código :

public function Main()
{
//creo las instancias
miRegistro          = new Registro();         
miDatabaseManager    = new DatabaseManager();   
miVentanaLibro       = new Ventana();              
//llamo al metodo xa meterdatos de bbdd en el registro
miDatabaseManager.cargar_datos(miRegistro);     

[..aqui sigue pero el code ya no viene al caso..]
}


el REGISTRO

Código :

   
public class Registro extends MovieClip
{
public var vble1 :Array;
public var vble2:Array;
      
      public function Registro()
      {
         //inicilizamos las vbles
         vble1       = new Array();
         vble2       = new Array();
      }      
}




DATABASEMANAGER():

Código :

public class DatabaseManager extends SQLConnection
{
var conn:SQLConnection;    //guardará la conexion SQL a la BBDD
var dbFile:File;          //guardará el PATh a la BBDD
var CarpetaBBDD:File; 
      
var puntero:Registro = new Registro;
      
   //constructor
   public function DatabaseManager()
   {
      [..aqui el code de carga de una base de datos sqlite..]
   }
      
         
   public function cargar_datos( puntero )
   {   
      //Ahora hacemos la consulta SQL
      [..]
                 puntero.vble1 = campo_bbdd1;
                 puntero.vble2 = campo_bbdd2;
      [..]
         }





He usado una vble llamada "puntero" recordando mis tiempos de C++.
Lo cierto es que haciendo trace(..) de los datos tanto desde dentro de DatabaseManager como desde Main me devuelven los mismos datos, así que todo parece correcto.
Pero la pregunta es... ¿es correctohacer eso en AS3?

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 25 Abr 2013 09:23 pm
Hola,
la idea de crear el registro es para no tener que crear una instancia de él cada vez que hay que usarlo en las diferentes clases. Si estudiaste C++, es como cuando en una clase creabas un miembro estático (ojo, no como las variables estáticas esas que no pierden el valor al salir del scope). Bueno, el caso es que si vas a tener que usar vble1 y vble2 en varias clases diferentes, puedes crear esta clase (OJO: No hace falta que extienda a MovieClip, ya que sólo va a contener estos datos):

Código ActionScript :

public class Registro
{
   public static var vble1:Array;
   public static var vble2:Array;
}

y después para acceder a ellas NO hay que crear una instancia, sino que directamente accedes a ellas con:

Código ActionScript :

Registro.vble1;
Registro.vble2;

Pero por lo que veo, si en tu caso sólo vas a necesitar acceder a variables que obtengan datos de la db, podrías prescindir de la clase Registro y meter esas variables estáticas dentro de la clase DatabaseManager, con lo que se puede hacer más simple (y de hecho es más lógico hacerlo así):

Código ActionScript :

public class DatabaseManager extends SQLConnection
{
   public var conn:SQLConnection;    //guardará la conexion SQL a la BBDD
   public var dbFile:File;          //guardará el PATh a la BBDD
   public var CarpetaBBDD:File; 
   
   public static var vble1:Array;
   public static var vble2:Array;
   
   public function DatabaseManager()
   {
      [..aqui el code de carga de una base de datos sqlite..]
      //Puedes cargar aquí los datos, si no van a variar y no te hará falta la función cargar_datos:
      DatabaseManager.vble1 = campo_bbdd1;
      DatabaseManager.vble2 = campo_bbdd2;
   }
}

Y cuando necesites usar estas variables tienes que poner:

Código ActionScript :

DatabaseManager.vble1;
DatabaseManager.vble2;

Por isidoro

Claber

498 de clabLevel

2 tutoriales

Genero:Masculino  

firefox
Citar            
MensajeEscrito el 25 Abr 2013 10:20 pm
Desde dentro de la clase DatabaseManager esto da error:

Código :

DatabaseManager.vble1 = campo_bbdd1;


En cambio esto sí funciona bien:

Código :

vble1 = campo_bbdd1;



Desde el Main() sí que funciona, entiendo que es así por ser variables de clase:

Código :

DatabaseManager.vble1[i]

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 26 Abr 2013 06:52 am
Debería funcionar (la próxima vez postea el error que te da, porque quizá no sea por eso). En realidad desde dentro de la propia clase DatabaseManager no te haría falta poner DatabaseManager.vble1, y sólo con vble1 funciona, pero es una buena práctica que al ser una variable estática lo pongas como te he puesto para dejar claro que es estática.
He hecho un ejemplo, y sí que me funciona.
También me he dado cuenta de que si no utilizas el constructor de DatabaseManager, con un método estático no te hará falta crear una instancia de esa clase.

Código ActionScript :

package 
{
   import flash.display.Sprite;
   
   public class Main extends Sprite 
   {
      public function Main() 
      {
         DatabaseManager.getDBData();
         
         trace("vble1 usada en Main: " + DatabaseManager.vble1);
         trace("vble2 usada en Main: " + DatabaseManager.vble2);
         
         var otraClase:OtraClase = new OtraClase();
      }
   }
}

package
{
   public class DatabaseManager
   {
      public static var vble1:Array;
      public static var vble2:Array;

      public static function getDBData():void
      {
         //[..aqui el code de carga de una base de datos sqlite..]
         DatabaseManager.vble1 = [0, 1];
         DatabaseManager.vble2 = [2, 3];
      }
   }
}

package 
{
   public class OtraClase 
   {
      public function OtraClase()
      {
         trace("vble1 usada en OtraClase: " + DatabaseManager.vble1);
         trace("vble2 usada en OtraClase: " + DatabaseManager.vble2);
      }
   }
}

Por isidoro

Claber

498 de clabLevel

2 tutoriales

Genero:Masculino  

firefox
Citar            
MensajeEscrito el 26 Abr 2013 03:46 pm
Muchas gracias de nuevo, cuando pase por casa lo probaré.

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 28 Abr 2013 01:56 pm
Bueno pues lo estuve probando de nuevo y ahora va perfecto ¿? no se porqué antes daba error.
Ahora tengo otro problema y es que tengo problema con las clases, no puedo ejecutar un método público de una clase desde otra y no acabo de entender porqué.

Además del Main() tengo estas 3 clases creadas:
*DatabaseManager()
*ClaseVentana() --> tiene vinculado un MC con campos de texto, donde se verán los datos de un cliente.
*ListadoLateral() --> crea un listado lateral de clientes en la BBDD


DatabaseManager() funciona sin problemas, carga los datos en memoria correctamente.
ClaseVentana() funciona sin problemas "manualmente".:

Código :

   
i=1; //es el indice del cliente en la BBDD
CampoTexto1.text = DatabaseManager.vble1[i];
CampoTexto2.text = DatabaseManager.vble2[i];
...


ListadoLateral() carga un listado de clientes en el lateral derecho de la pantalla., funciona bien.
-----------------------------------------------------------------------------------------------------------
Ahora viene el problema. Quiero que, al pulsar uno de los clientes del listado lateral, se carguen todos los datos de ese cliente en el MC de la instancia de Clase Ventana.
Programando estilo AS2 es sencillo, creo un listener que llame a una función que carga los datos en los campos de texto.
Pero con clases no se muy bien dónde debo poner el método.

* Si lo pongo en la clase del listado ListadoLateral(), no tengo acceso "directo" a los campos de texto, ya que son de una instancia de la clase Ventana.

* Si pongo el método en la clase ClaseVentana(), no se muy bien como llamarla desde la clase ListadoLateral(). He hecho el método público en la clase ClaseVentana():

Código :

public function cargaBuqueEnVentana():void 
{
i=1; //es el indice del cliente en la BBDD
CampoTexto1.text = DatabaseManager.vble1[i];
CampoTexto2.text = DatabaseManager.vble2[i];
...
}


Pero cuando lo llamo desde la clase ListadoLateral() me da error:

Código :

Llamada a un método cargaBuqueEnVentana posiblemente no definido mediante una referencia con tipo estático Class.


No entiendo el error. He hecho el "import ClaseVentana;" pero aparentemente una clase "no ve" a la otra y no puede acceder a sus métodos públicos.

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 29 Abr 2013 01:13 pm
Hola,
en AS3 también se hace como dices: ListadoLateral dispararía un evento al cambiar de usuario, que sería escuchado por ClaseVentana.
Si no quieres liarte, simplemente pásale al constructor de la clase ListadoLateral como parámetro la instancia de ClaseVentana, y lo almacenas dentro de una variable. Después, al cambiar de usuario le pasas a la función cargaBuqueEnVentana el índice del usuario seleccionado cargaBuqueEnVentana(userIndex).
De todos modos, ¿conoces Flash Builder ,o Flex? Con él puedes hacer eso que quieres más rápidamente, tanto el diseño de la ventana, el formulario, etc, como los "binding" de datos.

Por isidoro

Claber

498 de clabLevel

2 tutoriales

Genero:Masculino  

firefox
Citar            
MensajeEscrito el 29 Abr 2013 01:17 pm
Hola, lo cierto es que lo intenté pero no se porqué no funcionaba.
Al final he conseguido hacerlo funcionar con señales y eventos, luego posteo cómo lo he hecho, no se si es la mejor forma.

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 29 Abr 2013 01:59 pm
Bueno esto es lo que he hecho:

En la clase ListadoLateral:

Código :

//Listener para cuando seleccionamos una opción de la lista
private function clicEnListaUsuario(evento)
{
   //recoge la ID del USUARIO clickeado en el listadoy actualiza el idUsuarioActual
   DatabaseManager.idUsuarioActual = losDatos.getItemAt(miLista.selectedIndex).data;   
   //manda una señal al padre (clase MAIN) para que ejecute el codigo correspondiente
   //en este caso Main lanzará el método de VentanaLibro correspondiente a la carga de un USUARIO
   dispatchEvent( new NavigationEvent( NavigationEvent.CARGAUSUARIO ) );
   }


Esto recoge el ID de la BBDD del USUARIO y lo mete en una variable "global" llamada DatabaseManager.idUsuarioActual.

Ahora para transmitir la señal tengo creada una clase específica para enviar señales:

Código :

package 
{
   import flash.events.Event;
   
   public class NavigationEvent extends Event 
   {
      public static const CARGAUSUARIO:String       = "cargausuario";
      
      public function NavigationEvent( type:String )
      {
         super( type );
      }
   }
   
}


Y se recibe en MAIN que tiene lo siguiente:

Código :

public function muestrame_el_usuario( navigationEvent:NavigationEvent ):void
{
   miVentanaLibro.cargaUsuarioEnLibro();
}


De esta forma tan enrevesada lo consigo.
En realidad a mi me parece más "fácil" hacer una llamada desde una clase a la otra, sin pasar por el Main, pero me da error. Voy a probar lo que me has dicho de "pasar al constructor de la clase A como parámetro la instancia de la clase B..." a ver si me parece más natural.
Decir que uso Flash+FlashDevelop para el código.
Flex lo probé pero no me gustó, quizá más adelante, ahora mismo prefiero seguir con Flash.

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 29 Abr 2013 02:21 pm
Escribo de nuevo porque ya lo he hecho de la forma que me has comentado, pasando la instancia de una clase al constructor de otra como parámetro.

La forma que utilicé yo (eventos/señales) la saqué de éste magnífico tutorial:
[url=http://gamedev.michaeljameswilliams.com/2008/09/17/avoider-game-tutorial-1/][/url]

Está en inglés y trata sobre un hacer un juego muy básico, pero se aprende bastante.
El autor utiliza eventos/señales para pasar de una pantalla a otra.

Voy a seguir con la forma que me has propuesto que me parece más intuitiva, gracias de nuevo ^^

Por daniel69

78 de clabLevel



 

chrome
Citar            
MensajeEscrito el 29 Abr 2013 03:51 pm
Bueno, en realidad lo que te había posteado yo es la vía rápida y un poco chapucera de hacerlo porque no estaba seguro de si sabías hacerlo con eventos.
En tu caso se podía aplicar porque sólo tenías un ListadoLateral y una ClaseVentana, pero imagínate que mañana se te ocurre hacer que al cambiar de usuario en ListadoLateral se actualicen 2 o 3 ventanas diferentes (o te das cuenta de que para tu aplicación es mejor dividir ClaseVentana en varias subventanas).
Por eso es mejor hacerlo con la clase NavigationEvent que has creado. Eso sí, es mejor que a la clase NavigationEvent le pases también otro parámetro con los datos del nuevo usuario. Busca eventos con parámetros, o algo por el estilo (hace años alguien publicó un tutorial en Cristalab para hacerlo).
Si ya lo tienes implementado con eventos, mejor sigue con ellos. Sólo has tenido que crear 1 clase a mayores, y además, si estudiaste lo que es la encapsulación en c++, de esa forma no la rompes.
La idea es que en ListadoLateral, al seleccionar otro usuario se haga la consulta a la db, y después haces:

Código ActionScript :

dispatchEvent(new NavigationEvent(/*aquí procura meter todos los parámetros de Event, no sólo type*/), userData);

En ClaseVentana haces:

Código ActionScript :

addEventListener(event:NavigationEvent):void
{
    CampoTexto1.text = event.userData[0];
    CampoTexto2.text = event.userData[1];
}

Por isidoro

Claber

498 de clabLevel

2 tutoriales

Genero:Masculino  

firefox
Citar            
MensajeEscrito el 29 Abr 2013 05:29 pm
No sabía que se podían varios parámetros en los eventos, tendré que mirarlo.
Éste debe ser el tuto que decías:

http://www.cristalab.com/tutoriales/comunicacion-entre-clases-actionscript-3-con-eventdispatcher-c51078l/

En fin, ya había borrado lo de los eventos jeje. Volveré a ponerlo como estaba, que a la larga siempre será mejor. Gracias!!!

Por daniel69

78 de clabLevel



 

chrome

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.