Ir al contenido


Foto

Problemas pasar variables desde ventana Login al Principal


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

#1 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 04 diciembre 2012 - 07:32

Pues eso, la ventana de login la creo de esta manera:



delphi
  1. begin
  2.   if TFLogin.Execute then begin
  3.     Application.Initialize;
  4.     Application.MainFormOnTaskbar := True;
  5.     Application.CreateForm(TdmDatos, dmDatos);
  6.     Application.CreateForm(TFMain, FMain);
  7.     try
  8.       Application.Run;
  9.     except
  10.       On E:Exception do begin
  11.         ShowMessage(E.Message);
  12.       end;
  13.     end;
  14.   end;
  15. end.



Y en el login tengo lo siguiente:



delphi
  1. procedure TFLogin.btnEntrarClick(Sender: TObject);
  2. begin
  3.   IBGetUser.Close;
  4.   IBGetUser.ParamByName('NICK').AsString := edUser.Text;
  5.   IBGetUser.ParamByName('PASS').AsString := edClave.Text;
  6.   IBGetUser.Open;
  7.  
  8.   if IBGetUser.RecordCount > 0 then begin
  9.     ModalResult := mrOk;
  10.     IBDatabase.Close;
  11.     IBTrans.Active := False;
  12.   end else begin
  13.     N := N + 1;
  14.     MessageDLG('¡Nombre de Usuario o Contraseña es incorrecta!' + #13 + 'Por favor, intente de nuevo.' + #13 +
  15.               '¡Le quedan ' + IntToStr(3 - N) + ' intentos.!'  ,mtWarning,[mbOK],0);
  16.     if N = 3 then begin
  17.       ModalResult := mrAbort;
  18.     end;
  19.     Abort;
  20.   end;
  21. end;



¿Cómo puedo rellenar una variable pública en el formulario principal desde el login?, porque lo intento y me da el siguiente error:



delphi
  1. ---------------------------
  2. Debugger Exception Notification
  3. ---------------------------
  4. Project SiGesComb.exe raised exception class $C0000005 with message 'access violation at 0x007a624b: write of address 0x00000504'.
  5. ---------------------------
  6. Break  Continue  Help 
  7. ---------------------------



Saludos.

  • 0

#2 Fenareth

Fenareth

    Advanced Member

  • Administrador
  • 3.486 mensajes
  • LocationMexico City

Escrito 04 diciembre 2012 - 08:43

Por lo que veo, el FMain se crea hasta después de que se ejecuta el login y por ello no puedes hacer referencia a él sin que te mande el famoso access violation..

Se me ocurren dos cosas:

1. Que mandes llamar de diferente manera tu FLogin (en el evento OnShow del FMain, después de que éste haya sido creado).
2. Que declares la variable en una Unidad General y que después puedas mandarla llamar desde el FMain.

Saludox ! :)
  • 0

#3 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 04 diciembre 2012 - 08:54

Hola Fena, la primera opción fue lo primero que hice pero crea un efecto muy feo cuando cierras la aplicación desde el Login, el efecto es que el formulario principal aparece y se cierra, por lo que considero bastante feo, en cambio, tal como lo tengo evita esa situación.

Saludos.
  • 0

#4 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 04 diciembre 2012 - 09:01

Te adjunto un ejemplo de como lo hago yo sin problemas.

Las variables globales las pongo en el módulo de datos, donde siempre estarán disponibles para cualquier parte de la aplicación, luego al crear el form principal, simplemente obtiene el valor del módulo de datos.

Edito:Para corregir un error.
  • 0

#5 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 04 diciembre 2012 - 09:59

Muchas gracias Wilson, de nuevo me sirvió tus consejos (y)

Saludos.
  • 0

#6 FerCastro

FerCastro

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 636 mensajes
  • LocationCiudad de México

Escrito 04 diciembre 2012 - 11:12

Hola Ecumene

creo que todos tenemos nuestra manera de matar garrapatas. Lo que yo hago es crear una clase con los datos de uso general



delphi
  1. type TVariables = class
  2.           cNombreEmpresa      : String; // Empresa activa
  3.           cUsuario            : String;  // Usuario activo en el sistema
  4.           nIDUsuario          : Integer;
  5.           ...
  6.           ...
  7.  
  8.   end;



Luego creo una variable de este tipo en mi clase principal, en la sección pública:



delphi
  1.   public
  2.     oVariables: TVariables;



Lo primero que hago al crear la forma principal es instanciarla:



delphi
  1.   // Creamos el objeto con las variables de uso global
  2.   oVariables := TVariables.Create;



Y a partir de aqui estas variables quedan disponibles para todas las formas que hacen uso de la forma principal.

Obvio, debes crear siempre primero tu forma principal, y en el acceso sería algo asi:



delphi
  1.     if trim(DM.qAcceso.FieldByName('Contrasena').AsString) = Trim(cContra.Text) then
  2.         Begin
  3.           // Asignamos las variables globales
  4.           FMain.oVariables.cUsuario := Trim(DM.qAcceso.FieldByName('ClaveUsuario').AsString);
  5.           FMain.oVariables.nIDUsuario := DM.qAcceso.FieldByName('ID_Usuario').AsInteger;
  6.           FMain.oEstatusBar.Panels[0].Text := AnsiUpperCase(FMain.oVariables.cUsuario);
  7.           Valido := true;
  8.           close;
  9.         End



Mira, te mando el ejemplo si gustas, es algo que estuve desarrollando hace unos años y es lo que uso ahora en cada programa que hago. Para evitar problemas debes destruir todas tus formas, cerrar conexión a datos, todo eso al momento de cancelar desde el login.

Saludos!!
  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 diciembre 2012 - 11:51

Hola Ecumene

creo que todos tenemos nuestra manera de matar garrapatas. Lo que yo hago es crear una clase con los datos de uso general



delphi
  1. type TVariables = class
  2.           cNombreEmpresa      : String; // Empresa activa
  3.           cUsuario            : String;  // Usuario activo en el sistema
  4.           nIDUsuario          : Integer;
  5.           ...
  6.           ...
  7.  
  8.   end;



Luego creo una variable de este tipo en mi clase principal, en la sección pública:



delphi
  1.   public
  2.     oVariables: TVariables;



Lo primero que hago al crear la forma principal es instanciarla:



delphi
  1.   // Creamos el objeto con las variables de uso global
  2.   oVariables := TVariables.Create;



Y a partir de aqui estas variables quedan disponibles para todas las formas que hacen uso de la forma principal.

Obvio, debes crear siempre primero tu forma principal, y en el acceso sería algo asi:



delphi
  1.     if trim(DM.qAcceso.FieldByName('Contrasena').AsString) = Trim(cContra.Text) then
  2.         Begin
  3.           // Asignamos las variables globales
  4.           FMain.oVariables.cUsuario := Trim(DM.qAcceso.FieldByName('ClaveUsuario').AsString);
  5.           FMain.oVariables.nIDUsuario := DM.qAcceso.FieldByName('ID_Usuario').AsInteger;
  6.           FMain.oEstatusBar.Panels[0].Text := AnsiUpperCase(FMain.oVariables.cUsuario);
  7.           Valido := true;
  8.           close;
  9.         End



Mira, te mando el ejemplo si gustas, es algo que estuve desarrollando hace unos años y es lo que uso ahora en cada programa que hago. Para evitar problemas debes destruir todas tus formas, cerrar conexión a datos, todo eso al momento de cancelar desde el login.

Saludos!!


El disponer de una clase con la información global es una alternativa dentro de todo válida. El asunto es que es muy débil y volátil... sobre todo si uno corre el peligro de liberarla. O en todo caso, nada impide que se cree otra instancia de ésta y leer datos erróneos.
Por ello a estos tipos de clases se las debe de diseñar para que sean Singleton y no se permita ninguna instancia y que además se verifique que sólo se libere cuando se finaliza la aplicación.

En tu código en ningún momento tienes una clase global... Fíjate que defines la variable oVariable en la unidad de tu form principal. Con lo cual lo que haces es "atar" la existencia de oVariable al tiempo de vida del form principal (que no necesariamente el de la aplicación).

Otro peligro de tu código es que viola parcialmente la Ley de Demeter... Estás accediendo a los campos de oVariable desde tu Form. De modo que para acceder a dicha "clase global" desde cualquier otra unidad deberás pasar, necesariamente, a traves del form. Esto lleva a cosas como:



delphi
  1. OtroForm.Algo := FormPral.Global.CampoEnCuestion;



Uno de los principios de la ley de Demeter es "No hables con extraños"; y relacionado a ésto, el limitarse a los objetos inmediatos. No es sano tener que ir objeto.objeto.algo.
He visto ejemplos que hasta llegan a cosas como:



delphi
  1. Objeto.Objeto.Objeto.Propiedad.



La Ley de Demeter nos llama la atención y nos recuerda que en lo posible no hay que propagarse más allá del objeto a que necesitamos. ¿Porqué no directamente nos evitamos pasar por Form principal?



delphi
  1. OtroForm.Algo := Global.CampoEnCuestion;



En todo caso, si aún deseas hacer esta intermediación, para mantenerse "Demeter-cumpliance" lo más sano es que ahora Form principal disponga de algún método que facilite el acceso a la información global en cuestión... algo como:



delphi
  1. function TFrmPral.GetGlobalData(VariableName: string): string;



Y de este modo, basta con:



delphi
  1. OtroForm.Algo := FormPral.GetGlobalDate(CampoEnCuestion);



Pero claro... ahora resulta que se desaprovecha justamente la variable gobal. Y volvemos al principio.

Lo cierto es que si ya tienes una unidad UGlobales (que es lo más sano) con dicha clase, aprovecha ésta y define allí una instancia única:



delphi
  1. Unit UGlobal;
  2. ....
  3. var Global: TVariables;
  4.  
  5. initialization
  6.   Global := TVariables.Create;
  7.  
  8. finalization
  9.   Global.Free;



Si bien esto no impide que se definan otras variables del tipo TVariables, es una primera aproximación al singleton. Para algo más elaborado véase este documento.

Saludos,
  • 0

#8 FerCastro

FerCastro

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 636 mensajes
  • LocationCiudad de México

Escrito 04 diciembre 2012 - 01:04

El disponer de una clase con la información global es una alternativa dentro de todo válida. El asunto es que es muy débil y volátil... sobre todo si uno corre el peligro de liberarla. O en todo caso, nada impide que se cree otra instancia de ésta y leer datos erróneos.
--------------------------------------------
Por qué la tendrías que instanciar de nuevo?? no le veo motivo para hacerlo.
--------------------------------------------



Por ello a estos tipos de clases se las debe de diseñar para que sean Singleton y no se permita ninguna instancia y que además se verifique que sólo se libere cuando se finaliza la aplicación.


En tu código en ningún momento tienes una clase global... Fíjate que defines la variable oVariable en la unidad de tu form principal. Con lo cual lo que haces es "atar" la existencia de oVariable al tiempo de vida del form principal (que no necesariamente el de la aplicación).

--------------------------------------------
En mi caso, la forma principal está viva en todo el tiempo que la aplicación está viva.
--------------------------------------------

Otro peligro de tu código es que viola parcialmente la Ley de Demeter... Estás accediendo a los campos de oVariable desde tu Form. De modo que para acceder a dicha "clase global" desde cualquier otra unidad deberás pasar, necesariamente, a traves del form. Esto lleva a cosas como:



delphi
  1. OtroForm.Algo := FormPral.Global.CampoEnCuestion;



Uno de los principios de la ley de Demeter es "No hables con extraños"; y relacionado a ésto, el limitarse a los objetos inmediatos. No es sano tener que ir objeto.objeto.algo.
He visto ejemplos que hasta llegan a cosas como:



delphi
  1. Objeto.Objeto.Objeto.Propiedad.



La Ley de Demeter nos llama la atención y nos recuerda que en lo posible no hay que propagarse más allá del objeto a que necesitamos. ¿Porqué no directamente nos evitamos pasar por Form principal?



delphi
  1. OtroForm.Algo := Global.CampoEnCuestion;



En todo caso, si aún deseas hacer esta intermediación, para mantenerse "Demeter-cumpliance" lo más sano es que ahora Form principal disponga de algún método que facilite el acceso a la información global en cuestión... algo como:



delphi
  1. function TFrmPral.GetGlobalData(VariableName: string): string;



Y de este modo, basta con:



delphi
  1. OtroForm.Algo := FormPral.GetGlobalDate(CampoEnCuestion);



Pero claro... ahora resulta que se desaprovecha justamente la variable gobal. Y volvemos al principio.

Lo cierto es que si ya tienes una unidad UGlobales (que es lo más sano) con dicha clase, aprovecha ésta y define allí una instancia única:



delphi
  1. Unit UGlobal;
  2. ....
  3. var Global: TVariables;
  4.  
  5. initialization
  6.   Global := TVariables.Create;
  7.  
  8. finalization
  9.   Global.Free;



Si bien esto no impide que se definan otras variables del tipo TVariables, es una primera aproximación al singleton. Para algo más elaborado véase este documento.

Saludos,




Al final, cada quien resuelve el problema como mejor le acomoda, no? quiero decir, posiblemente no esté siguiendo todas las reglas de programación, pero sinceramente, prefiero esto al uso de variables de tipo global.

Saludos!!
  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 diciembre 2012 - 04:03

Por qué la tendrías que instanciar de nuevo?? no le veo motivo para hacerlo.

Si lees bien dije claramente :

O en todo caso, nada impide que se cree otra instancia de ésta y leer datos erróneos


Es decir, que puede suceder, que es distinto que tu lo hayas hecho y sea el caso.
Simplemente acoté que es un potencial peligro si uno no tiene el debido cuidado. Hoy quizá no cometas ese error, pero luego para cuando pase el tiempo y revises el mar de código y te pierdas es cuando surgen cosas como las que he descrito.
Basta con recorrer los foros para leer historias de objetos perdidos, duplicados y/o mala asignación de datos.

En mi caso, la forma principal está viva en todo el tiempo que la aplicación está viva.


Para aquellas clases que deben hacer uso constante o reiterado de datos que proviene de otra, lo de esperar es que tenga alguna visibilidad de atributo, o en otro caso de parámetro, que referencie a ésta. De este modo basta con hacer como:



delphi
  1. MiVariable1 := FGlobal.Variable1;



Siendo FGlobal un atributo del tipo TVariable:



delphi
  1. Type
  2.   TfrmMain = class...
  3.   private
  4.     FGlobal: TVariable;
  5.   ...



Y si se quiere, y hasta quizá sea lo más recomendable, se define una propiedad que le aporta más seguridad al acceso a dicho campo.
Estas clases no debiera liberar este objeto, es más, hasta se puede diseñar para que no asuma el control de crearla. De hecho todo apunta, léase sobre "Experto en Información" y "Hacerlo Yo Mismo", a que quien cumple el rol de crear instancias de TVariable es la propia. O más formal, el llamado Singleton.

De ese modo la clase interesada en saber algo sobre alguna "variable global" mantiene la referencia a la "clase global" y no hay necesidad alguna de tener que pasar por el form.

Y listo, ahora nada de intermediarios. Hay tienes, he dado 2 opciones (no necesariamente exclueyentes) o maneras de evitar más acoplamiento, y que hasta incluso... un acoplamiento que podría ser innecesario.
1) Disponer un Singleton y que los interesados les soliciten a éste único objeto global.
2) Tener una variable de atributo que referencie a un objeto del tipo TVariable.

Estas opciones están pensadas para reducir el acoplamiento. Acoplamiento que hasta podría ser innecesario, y lleva a un código más estable, seguro y del que no hay que estar tan pendiente de los tiempos de vida de una clase para garantizar el acceso a un punto que desde un principio está pensado en ser global.
En tu propuesta ahora todo el que requiera de dicho recurso global resulta que debe pasar por el form principal primero. Entonces, ahora no sólo resultas que el resto de tus otros formularios ven incrementado su acoplamiento en 2: uno por el form principal, y otro por la clase global.

Pero además, y lo que es lo peor de todo, es ilógico tu diseño... Por un lado creaste una clase para tener en ella información global, pero a su vez la has "ocultado" su fácil acceso al asociarla a un form.
Piensa GLOBAL es GLOBAL. ¡No debes de ocultarla! A la larga es más problemático, ya no sólo tienes a tu clase global, sino que ahora ¡también lo es y debe serlo la form principal! Y no siempre es bueno que un form tenga este comportamiento.

Al final, cada quien resuelve el problema como mejor le acomoda, no? quiero decir, posiblemente no esté siguiendo todas las reglas de programación, pero sinceramente, prefiero esto al uso de variables de tipo global.

Las variables globales no son un peligro por propia naturaleza. Son un peligro si uno no las usa adecuadamente.
Y te voy diciendo que ya que quieres evitarte el uso de variables de tipo globales... Dime que es lo que ves en



delphi
  1. var
  2.   form1: TForm1;



O en tus


delphi
  1. var frmMain: TFrmMain;



¿No es acaso esto una variable con comportamiento global cuando ahora TODOS los demás formularios deban invocar a ésta para pedirle algo que en realidad es para pedirle a otro?

Me parece que te tomaste demasiado personal mi comentario FerCastro.
Bien dices que cada uno toma las armas a como las puede usar, pero me parece que te falta. Te falta aprender que hay otras maneras, y más seguras y estudiadas. Hay que hacer un esfuerzo por hacer las cosas mejor y no simplemente a lo pelos.

Hay una cita que dice: "Hay dos formas de diseñar software: la primera es hacerlo tan simple que obviamente no hay deficiencias y la segunda es hacerlo tan complicado que no hay deficiencias obvias. La primera forma es mucho más difícil." de C.A.R Hore y otra de un tipo conocido por ser un gran crítico y gran especialista, "Cualquier tonto puede escribir código que un ordenador entiende. Los buenos programadores escriben código que los humanos pueden entender.", Martin Flower. U otra forma de decirlo: "Mucho del software hoy en día se parece a una pirámide egipcia: con millones de ladrillos apilados uno encima del otro, sin integridad estructural y hecho por pura fuerza bruta y miles de esclavos." de Alan Kay.

En cierta forma, estos grandes de la programación dicen que hay que tener bien pensado las cosas. Y no hay peor control en un software que un mal equilibrio entre acoplamiento y la cohesión. Negar esto es como ir por un barco a la deriva sin un plano.
No siempre lo que te parece simple y a como uno le sale es la mejor opción. Tenlo presente.

Lo digo en buen plan FerCastro. Yo no soy un experto en el tema, pero la poca experiencia que he tenido me ha dicho que es mejor escuchar a la Ingeniería de Software y sus buenas prácticas. Y hay quienes lo han resumido muy bien:

"Las buenas personas son más importantes que cualquier proceso. Buenas personas con un buen proceso siempre actuarán mejor que buenas personas sin procesos." Grady Booch

Hay que despertar el sentido crítico en todo momento y desarrollo de un software.

Saludos,
  • 0

#10 ELKurgan

ELKurgan

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 566 mensajes
  • LocationEspaña

Escrito 04 diciembre 2012 - 11:47

Por si os sirve de algo, yo lo que hago es crear el DataModule primero, y ahí es donde tengo la variable/clase global.

Luego llamo al Login, y si es correcto, entro en el programa; si es incorrecto, destruyo el DataModule y listo (si no hago esto, me produce también un Access Violation al cerrar la aplicación):



delphi
  1. Application.CreateForm(TDMDatos, DMDatos);
  2.   if TLoginForm.PermitirAcceso then
  3.   begin
  4.     Application.CreateForm(TFrmPrincipal, FrmPrincipal);
  5.     Application.Run;
  6.   end
  7.   else
  8.   begin
  9.     DMDatos.Free;
  10.   end;



Un saludo
  • 0

#11 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 05 diciembre 2012 - 06:05

Al final, cada quien resuelve el problema como mejor le acomoda, no? quiero decir, posiblemente no esté siguiendo todas las reglas de programación, pero sinceramente, prefiero esto al uso de variables de tipo global.


A ver mi amigo FerCastro, aquí tenemos un problema de semántica, si hilas delgado, independientemente de como accedas a ellas no dejan de ser variables ni dejan de ser globales, observa que el uso de variables de tipo global no es cosa de que prefieras o no usarlas, en muchas aplicaciones son "estrictamente necesarias", el ejemplo más típico (en una aplicación cliente) son un par de variables para almacenar el nombre del usuario logueado y su ID, que tienen que ser visibles desde muchas partes del programa; lo que realmente importa es la implementación que hagas para almacenar y acceder a dichas variables, ahora bien dicha implementación podría residir arbitrariamente en cualquier unit del programa, basta con agregar la unit en cuestión al lugar donde la necesites, por su puesto que por cuestiones de orden y buenas prácticas escogerás el lugar más idóneo para hacerlo.

En una aplicación cliente que se conecta a una base de datos de las de  toda la vida de Delphi, lo más normal es que haya un módulo de datos que en la mayoría de los casos dejemos que Delphi lo cree automáticamente, ahora bien,  la unit (no la clase del módulo) donde reside el módulo, bien podría albergar la implementación para almacenar y acceder a las famosas variables.

Dicha implementación podría ser tan simple como declarar las variables con nombres que no admitan ambigüedades en la sección interface de la unit y asegurarse de llamarlas por su nombre completo Unit.NombreVariable, o implementaciones con la complejidad que desees y necesites, como dice nuestro amigo EliseoGN alias Egostar  :D,  depende, depende, depende, del tipo de aplicación.

Considero muy acertadas y fundamentadas las  observaciones que hace Delphius acerca de la implementación que propones.

Un cordial saludo.

PD: Que bueno sería que nuestro amigo Delphius (amante y obsesivo con las buenas prácticas) nos regalara un pequeñísimo ejemplo de una implementación simple de cómo almacenar y acceder técnicamente a una variable global. (Eso sí, sin adentrarnos demasiado en los vericuetos teóricos de los patrones  :D :D).
  • 0

#12 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 05 diciembre 2012 - 07:12

Dicha implementación podría ser tan simple como declarar las variables con nombres que no admitan ambigüedades en la sección interface de la unit y asegurarse de llamarlas por su nombre completo Unit.NombreVariable, o implementaciones con la complejidad que desees y necesites, como dice nuestro amigo EliseoGN alias Egostar  :D,  depende, depende, depende, del tipo de aplicación.


Bueno, si suelo meterme en donde no me llaman, ahora que se me nombra, pues no podía desaprovechar :)

Y si, coincido, a veces no es necesario tanta parafernalia para resolver el asunto, se puede usar variables globales, clases o records, sin embargo, yo creo que todos tenemos ya nuestra unidad de clases, variables y métodos genéricos para cualquier aplicación que desarrollemos.

Coincido con Fernando de que "cada quien sabe donde le aprieta el zapato", pero también coincido con el buen amigo Marchelo, hay que tener cuidado con nuestros actos.

Es decir, depende, depende, depende :D :D :D

PD: Que bueno sería que nuestro amigo Delphius (amante y obsesivo con las buenas prácticas) nos regalara un pequeñísimo ejemplo de una implementación simple de cómo almacenar y acceder técnicamente a una variable global. (Eso sí, sin adentrarnos demasiado en los vericuetos teóricos de los patrones  :D :D).


Me adhiero a la petición, amigo Marchelo, deje un poco la teoría y muestrenos algo de código, no sea usted envidioso :D :D :D

Saludos
  • 0

#13 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 05 diciembre 2012 - 08:30

PD: Que bueno sería que nuestro amigo Delphius (amante y obsesivo con las buenas prácticas) nos regalara un pequeñísimo ejemplo de una implementación simple de cómo almacenar y acceder técnicamente a una variable global. (Eso sí, sin adentrarnos demasiado en los vericuetos teóricos de los patrones  :D :D).


Me adhiero a la petición, amigo Marchelo, deje un poco la teoría y muestrenos algo de código, no sea usted envidioso :D :D :D


El uso y acceso de las variables globales no tiene tanta ciencia. Y creería que no hace falta demasiado ejemplo para demostrar el principio. Basta con disponer de una unit UGlobales y en ella disponer las variables, clases, records, o la estructura que uno considere oportuno. Luego en cada unidad o módulo que requiera hacer uso basta con añadirle en su sección uses UGlobales para tener el acceso.

Lo que uno haga ya dentro de la unidad global es más una cuestión de diseño y gustos. En lo que si debo de hacer una advertencia es si emplea una clase real-singleton a como se describe en el artículo que enlacé anteriormente. Esta clase si bien admite la herencia, tiene el defecto de que al haber alterado NewInstance ya no es posible tener dos instancias diferentes de sus descendientes... o se crea una u otra. Por ejemplo digamos que me creo un TVariableAbstracto rea-singleton y luego se me da la loca de definir un TVariableRol, TVariableUsuario y un TVariablePermisos que hereden de éste. El resultado será que se creará una única instancia de alguna de estas 3 nuevas clases. Esto es así debido al principio que rige en un Singleton: una única instancia... ni más ni menos, ya sea de un TAnimal, o un TPerro; sólo una.

Mis comentarios sobre lo que sugiere la Ley de Demeter es justamente una manera de demostrar el mal camino que se puede cometer cuando hacemos OO. Uno de ellos es justamente hablar con un extraño. Como he argumentado antes, en el ejemplo de FerCastro "OtroForm" se ve obligado a hablar con el form principal para finalmente hablar directamente con la instancia de TVariables.
La Ley de Demeter ofrece unos principios esenciales que ayudan a diseñar clases de una manera que mantengan el menor acoplamiento posible. Si bien no es estrictamente necesario seguir estos principios (de hecho se podría argumentar un contraejemplo de cuando la Ley de Demeter no es aplicable) en la gran inmensa mayoría de las ocasiones es más que saludable tenerlos presente y aplica.

Cuando uno va a hacer cualquier diseño OO en cierta forma está haciendo uso de la Ley de Demeter.

Los patrones son otra de las herramientas que pueden ayudar a estructurar de una manera más apropiada nuestras clases. La mayoría de ellos (por no decir todos) tienen como norma ser Demeter-cumpliance, y en forma más general respetando las Variaciones Protegidas, y equilibrar el Acoplamiento y la Cohesión. No es necesario aplicar patrones para mi argumentación, pero es que justamente hay dos patones que apoyan mi tesis: Experto en Información y Hacerlo Yo Mismo. ¿Quien tiene la información de las variables globales? La clase global, ¿Quien debe por tanto cumplir el rol de crear ésta? Yo misma. Ergo, ambos apuntan justamente a que se evita aumentar la indirección y el acceso a esta clase.

Otra razón que puede presentarse para separar el diseño de FerCastro del form principal de la clase global es la cohesión. En principio un Form debiera limitarse a su contexto: tener las acciones necesarias para dar forma a cuestiones de interfaz. Cuando uno le asocia, sobre todo si declara en éste una variable, una clase global que tiene como rol el mantener datos está mezclando los intereses de interfaz con el de la capa de datos.

En mis propuestas pueden verse ambas cosas:
1) Disponer del Singleton. Este diseño aporta bajo acoplamiento, ahora cada unidad interesada simplemente añade en uses la unidad global e invoca al singleton cuando requiera hacer uso.

2) Y que cada interesado mantenga referencia a la clase global. Este diseño si bien sigue aportando bajo acoplamiento, ahora resulta que las clases interesadas perderán un poco de cohesión.

Ya es cosa de análisis que opción es mejor. En ocasiones por cuestiones técnicas y de diseño necesariamente debe llevarse al caso 2.

De todas formas, sea cualquiera de éstas, con ambas se garantiza lo que sugiere Demeter, no hablas con extraños y te limitas a hablar con tus inmediatos. No es lo mismo con el ejemplo de FerCastro, en donde el acoplamiento es mayor debido a que cada unidad/clase que deba hacer uso de la clase global debe añadir dos unidades (una de ellas a las fuerzas) y que además se ha reducido intencionalmente la cohesión del formulario principal (Ya que éste asume ahora el control de crear dicha clase, y mezcla intereses de interfaz con el de datos).

Cuando son pocos formularios, podría aceptarse la propuesta de FerCastro pero con cada nuevo form, el acoplamiento final crece el doble... al punto en que el acoplamiento general se vuelve inmanejable.

A como a dicho Wilson, las variables globales son necesarias, hasta incluso no se las puede evitar (de hecho, en nuestras aplicaciones gráficas nos estamos llevando una que a veces ni nos damos cuenta... Application  ;) ). Y a como he dicho, el problema no son las variables globales... sino un mal uso y control de las mismas.

Si en verdad quieren un ejemplo, me van a tener que esperar. A ver si hago un lugarcito.

Saludos,
  • 0

#14 FerCastro

FerCastro

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 636 mensajes
  • LocationCiudad de México

Escrito 05 diciembre 2012 - 11:17


Me parece que te tomaste demasiado personal mi comentario FerCastro.
Bien dices que cada uno toma las armas a como las puede usar, pero me parece que te falta. Te falta aprender que hay otras maneras, y más seguras y estudiadas. Hay que hacer un esfuerzo por hacer las cosas mejor y no simplemente a lo pelos.


Para de sufrir compañero :),  cómo piensas que me voy a tomar un comentario personal si no te conozco, y me estás aclarando algunas cosas?

A ver, solo digo que me funciona, y tu explicación es buena y  tus comentarios atinados,  jamás dije que yo tuyo fuera malo o que lo mío era la mejor solución, solo aporté algo que a mi me sirve.

Saludos!! y gracias por lo tips.
  • 0

#15 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 05 diciembre 2012 - 11:32

Para de sufrir compañero :),  cómo piensas que me voy a tomar un comentario personal si no te conozco, y me estás aclarando algunas cosas?

A ver, solo digo que me funciona, y tu explicación es buena y  tus comentarios atinados,  jamás dije que yo tuyo fuera malo o que lo mío era la mejor solución, solo aporté algo que a mi me sirve.

Saludos!! y gracias por lo tips.

Por un momento pensé que lo habías tomado como un ataque.
Mis más sinceras disculpas si te ha parecido prepotente mi forma de explicarme.

Yo una vez hice algo como tu propuesta, pero luego me dije que al final se podía hacerlo de otra forma más directa. Casualmente, en ese entonces era cuando más estaba leyendo sobre Variaciones Protegidas, y los patrones en general.

Saludos,
  • 0

#16 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 05 diciembre 2012 - 01:28

Para de sufrir compañero...................


Caramba!!! por un momento pensé que ibamos a ver al compañero "Mapache do Nascimento" en la TV :D :D :D

Saludos
  • 0

#17 FerCastro

FerCastro

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 636 mensajes
  • LocationCiudad de México

Escrito 06 diciembre 2012 - 11:48

Caramba!!! por un momento pensé que ibamos a ver al compañero "Mapache do Nascimento" en la TV :D :D :D
Saludos


ELISEO!! TOMA EL BILLETE MÁS GRANDE QUE TENGAS EN TU BILLETERA, TOMALO Y DESPRENDETE DE EL!!! AHORA CORRE INMEDIATAMENTE Y DEPOSITALO A MI CUENTA!! ES PARA LA OBRA DE SAN MAPACHE ARCANGEL!!!!


  • 0

#18 FerCastro

FerCastro

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 636 mensajes
  • LocationCiudad de México

Escrito 06 diciembre 2012 - 11:53

Por un momento pensé que lo habías tomado como un ataque.
Mis más sinceras disculpas si te ha parecido prepotente mi forma de explicarme.
Yo una vez hice algo como tu propuesta, pero luego me dije que al final se podía hacerlo de otra forma más directa. Casualmente, en ese entonces era cuando más estaba leyendo sobre Variaciones Protegidas, y los patrones en general.
Saludos,


Mi estimado, no no para nada, en verdad que nada más alejado de la realidad!! jamás lo tomé como un ataque. Y con respecto de sonar prepotente... de que país me dijiste que eres?? JAJAJAJA!! es broma amigo, es broma.

Saludos!
  • 0




IP.Board spam blocked by CleanTalk.