Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Evitar variables globales.... (https://www.clubdelphi.com/foros/showthread.php?t=74963)

Casimiro Notevi 26-07-2011 00:23:29

Por cierto, ¿quién es JMR?

roman 26-07-2011 16:32:22

¿No es de esos foreros míticos que por alguna razón que se pierde en la oscuridad del pasado salió del Club?

maeyanes 26-07-2011 18:47:48

Yo recuerdo a JMR de las listas de discusión, cuando esto se manejaba por listas de distribución por email.


Saludos...

marcoszorrilla 26-07-2011 22:25:42

JMR. José Manuel Rodriguez es el autor de las famosas "Trivial", también fue moderador del Club Delphi, fue una pena que se perdiera su concurso en este sitio, pero así son las cosas, hace un tiempo vi que estaba en la lista de FireBird, pero hace tiempo que no he vuelto a saber de él.

Un Saludo.

Casimiro Notevi 26-07-2011 23:49:06

¿Y eso de las variables globales era un documento que escribió o fue algún post en algún foro?, por echarle un vistazo.

marcoszorrilla 27-07-2011 06:52:52

Creo recordar que era un hilo normal en el que por algún motivo salio el tema de las variables y yo dije que las colocaba en el Menú.

Un Saludo.

Paoti 28-07-2011 19:04:27

Vairable Gloables como Variables Estaticas.
 
¡Hola Dudes!

Como ven este acercamiento.

Creando, por así decirlo una propiedad estatica de una clase, y asignarle su valor, que estará visible en todas las unidades (y por ende Forms) donde se requiera.

Espero el cógido sea más legible que mi explicación:


la unidad donde se almacenarán las propiedades globales, por así decirlo
Código Delphi [-]
unit uGlobales;

interface

type
TGlobales = class
private
    // procediminto y función para leer la varables
    // se antepone Class, para indicar que son métodos de clase y on de objeto
    class function GetUsuario : string;
    class procedure SetUsuario(const Value: string);
protected

public
  // Es una propiedad de clase y no de objeto, debido a que usa metodos de clase
  property Usuario : string read GetUsuario write SetUsuario;

published
  { published declarations }
end;

implementation

var
    FUsuario : string;


class function TGlobales.GetUsuario: string;
begin
      Result := FUsuario;
end;

class procedure TGlobales.SetUsuario(const Value: string);
begin
  FUsuario := Value;
end;

end.


Ahora, cuando quieras acceder al valor de la propiedad, o en su defecto asigarle un valor solo tienes que hacer lo sigiuente.

Código Delphi [-]
implementation

uses
  uGlobales;

......

// desde un formulario 2
procedure TForm2.btn1Click(Sender: TObject);
var
  myGlobal : TGlobales;
begin
  Caption := myGlobal.Usuario;
end;

......

// desde un formulario 1
procedure TForm1.btn1Click(Sender: TObject);
var
  myGlobal : TGlobales;
begin
myGlobal.Usuario := 'Paoti';
end;

Dudas, comentarios.

Estará bien esta forma de realizarlo, digo, no lo he puesto en practica en un ambiente de producción.


Gracias.

roman 28-07-2011 19:54:04

A mi me parece muy bien. Esta es una forma de implmentar propiedades estáticas (simuladas) en una clase de Delphi. Creo que las versiones recientes ya admiten este tipo de propiedades.

// Saludos

andres1569 28-07-2011 20:13:05

Interesante técnica :), sin necesidad de crear ni destruir ningún objeto, che !

Neftali [Germán.Estévez] 29-07-2011 15:42:59

Cita:

Empezado por Paoti (Mensaje 407751)
Estará bien esta forma de realizarlo, digo, no lo he puesto en practica en un ambiente de producción.

Yo no acabo de verle la lógica. Usas una clase Global para acceder a una variable, que en lugar de estar dentro de la clase está fuera.

(1) No le veo ventajas (seguramente es que yo no las veo), pero las hay, entre lo que has puesto tú y esto:

Código Delphi [-]
TGlobales = class private
    FUsuario : string;   <<<<====

     // procediminto y función para leer la varables    
    // se antepone Class, para indicar que son métodos de clase y on de objeto     
    class function GetUsuario : string;     
    class procedure SetUsuario(const Value: string); 
  protected 
  public   
   // Es una propiedad de clase y no de objeto, debido a que usa metodos de clase   
   property Usuario : string read GetUsuario write SetUsuario; 
  published 
end;

(2) Lo segundo que no veo es qué ventajas tiene en este caso usar la clase, respecto a esto:

Código Delphi [-]
unit uGlobales; 
interface 
 var Usuario : string;
implementation 
end.

Y cuando la uses poner

Código Delphi [-]
Caption := uGlobales.Usuario;
...
uGlobales.Usuario := 'pepe';

roman 29-07-2011 17:00:26

A ver si aclaramos un poco:

Una forma de manejar variables de ámbito global sin ser propiamente globales, es encapsularlas en una clase como propiedades estáticas, esto es, como propiedades que no dependen de ningua instancia particular y que, por tanto, pueden usarse sin tener que crear un objeto de la clase.

El punto es que hasta delphi 2010, creo, no había propiedades estáticas -como sí las hay en otros lenguajes. Entonces, para simularlas, se hacía lo que propone Paoti. La variable a la que se accede desde la clase está restringida al ámbito privado de la unidad en la que se declara y, por tanto y es lo importante, no es accesible directamente desde fuera, lo cual, proporciona un cierto grado de control sobre dicha variable. Cosa que no ocurre si simplemente se usa una variable declarada en la sección interface. La variable queda "expuesta" a todo mundo.

Si tal variable se pone "dentro" de la clase, entonces no sería posible usarla sin instanciar un objeto de la clase. Dicho de otra forma, ya no sería una propiedad estática de la clase.

// Saludos

Paoti 29-07-2011 17:13:22

El (1) no funciona, como variable privada, debe ser de la forma como está la clase expuesta por mi anteriormente.

el (2) es otra forma, usando propiedades estáticas simuladas.

Ahora, el ejemplo anterior, del post, es cómo usar otro tipo de Variables Globales, sí no quieres usar la forma tradicional.

Neftali [Germán.Estévez] 29-07-2011 17:22:27

Cita:

Empezado por Paoti (Mensaje 407894)
El (1) no funciona, como variable privada, debe ser de la forma como está la clase expuesta por mi anteriormente.

Correcto.
En ese caso hay que definir una variable global del tipo TGlobales, como comenté antes.

De todas formas, sigo viéndolo "raro".

Chris 29-07-2011 17:26:06

Interesante pauti.

Pero no entiendo el por qué de este código:
Código Delphi [-]
// desde un formulario 2
procedure TForm2.btn1Click(Sender: TObject);
var
  myGlobal : TGlobales;
begin
  Caption := myGlobal.Usuario;
end;

......

// desde un formulario 1
procedure TForm1.btn1Click(Sender: TObject);
var
  myGlobal : TGlobales;
begin
myGlobal.Usuario := 'Paoti';
end;

Cuando simplemente se podría hacer así, según una clase de muestra que he escrito:

Código Delphi [-]
    TGlobalVars = class
        private
            class var FVar1: String;
        public
            class property Var1: String read FVar1 write FVar1;
            // o simplemente:
            class var Var2: String;
    end;

// -------------------------------------------------------//
implementation

procedure TForm2.Button1Click(Sender: TObject);
begin
    TGlobalVars.Var1 := Edit1.Text;
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
    ShowMessage(TGlobalVars.Var1);
end;

roman 29-07-2011 17:32:10

Es que no hay que definir ninguna variable del tipo TGlobales. Simplemente se hace:

Código Delphi [-]
TGlobales.Usuario := 'roman';

Edito:

¡Ah! Veo que Chris ya lo mencionó :)

// Saludos

roman 29-07-2011 17:35:50

Sólo añadir que, con esta técnica, dado que el acceso es vía métodos de una clase, se puede tener un mejor control, validación, etc. Incluso pueden implementarse variables "globales" de sólo lectura, por ejemplo.

// Saludos

Paoti 29-07-2011 17:59:30

¡Hola compañeros!

Me gusta tu idea roman, para evitar usar ahora sí, variables globales


Por ejemplo, una idea sería la siguiente:

Código Delphi [-]

TGlobales.CadenaConexion := 'lcoalhost:baseDatos';
TGlobales.Inicializa('usario', 'pAssW0rd');
TieneAcceso := TGLobales.Activo;
Perfil := TGloables.Perfil;
ultimoAcceso := TGlobales.FEchaUltAcceso


el método Inicializa(), incializa los valores de las propiedades de clase, que serán Globales, y de solo lectura. en base a los datos de la base de datos. y están disponibles en todos lados donde se haga referencia la unidad.

Neftali [Germán.Estévez] 29-07-2011 18:16:56

Yo personalmente hubiera hecho algo así (en realidad es lo que hago).

Sigues manteniendo las propiedades de lectura/escritura de las diferentes variables (ya que eso te lo da la clase), y colocas las variables "dentro" de la clase en lugar de fuera.

Mantienes una variable Global del tipo TGlobales, pero es que de la otra forma también mantienes en memoria todas las variables necesarias. No le veo diferencia en eso.

Código Delphi [-]
unit Globales;

interface

type
  TGlobales = class
  private
    FUsuario : string;
    FCadenaConexion: string;
    FPassWord: string;

    // procediminto y función para leer la varables
    // se antepone Class, para indicar que son métodos de clase y on de objeto
    function GetUsuario : string;
    procedure SetUsuario(const Value: string);
    function GetPassWord: string;
  protected

  public
    // Es una propiedad de clase y no de objeto, debido a que usa metodos de clase
    property Usuario : string read GetUsuario;
    property Password: string read FPassWord;
    property CadenaConexion:string read FCadenaConexion write FCadenaConexion;

    procedure Inicializa(Us,psw:String);
  published
  { published declarations }
  end;

var
  uGlobales:TGlobales;

implementation

uses
  SysUtils;


function TGlobales.GetUsuario: string;
begin
  Result := FUsuario;
end;

procedure TGlobales.Inicializa(Us, psw: String);
begin
  FUsuario := us;
  FPassWord := psw;
end;

procedure TGlobales.SetUsuario(const Value: string);
begin
  FUsuario := Value;
end;

Initialization
  uGlobales := TGlobales.Create();

Finalization
  FreeAndNil(uGlobales)

end.

roman 29-07-2011 18:41:58

La diferencia es que en tu caso debes crear un objeto de esa clase siendo que los datos a los que accedes no dependen realmente de un objeto en particular sino de la clase en sí.

Idealmente se tendría algo así:

Código Delphi [-]
type
  TGlobal = class
  private
    class var FUsuario: String; // <--- Esto no es posible
    class function GetUsuario: String;

  public
    property Usuario: String read GetUsuario;
    class procedure Inicializa;
  end;

implementation

class function TGlobal.GetUsuario: String;
begin
  Result := FUsuario;
end;

class procedure TGlobal.Inicializa;
begin
{
  Aquí se leen los valores de un archivo INI o de la base de datos, etc.

  Este método podría llamarse, por ejemplo, en la inicialización de la unidad.
}
end;

Y, entonces, para usar esos datos lo haces directamente de la clase:

Código Delphi [-]
Caption := TGlobal.Usuario;

Pero, como delphi no permitía las variables de clase, es que se simulan haciendo lo que dice Paoti.

Desde luego que la clase, tal como la usas tú, instanciando un objeto, tampoco es que esté mal. Al final de cuentas cumple con el objetivo de evitar el uso de variables globales.

// Saludos

maeyanes 29-07-2011 18:50:17

Hola...

Y usando el ejemplo de roman en Delphi 2010 y posteriores:

Código Delphi [-]
TGlobal = class
  // ...
public
  class constructor Create; // constructor de clase
end;

implementation

class constructor TGlobal.Create;
begin
  {
  Aquí se leen los valores de un archivo INI o de la base de datos, etc.

  Este constructor se llama automáticamente la primera vez que se quiere usar esta clase.
  }
end;


Saludos...


La franja horaria es GMT +2. Ahora son las 17:38:58.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi