PDA

Ver la Versión Completa : El mejor momento para liberar un objeto


BDWONG
04-12-2014, 01:15:00
Bueno no sabia que poner de titulo, asi que si algún moderador encuentra uno mejor que explique mi pregunta que lo modifique por favor.

Bueno mi pregunta es que yo tengo un programa que tiene un clase(objeto) que contiene metodos para cifrar texto plano ejemplo : xor, rotn,reverse, rc4 etc.

mi pregunta viene a que si que cuando llamo al objeto TCifrado y quiero utilizar sus metodos es necesario que al momento de llamar que cree el objeto y en ese mismo instante despues de utilizarlo libere el objeto o la otra opcion que se me viene a la cabeza es que cree el objeto en el formcreate y libere el objeto al cerrar el form

La verdad es algo sin mucho sentido pero imagínense que tenga 20 métodos diferentes y aveces puedo ocupar uno u otro
espero sus respuestas saludos...

Aqui la clase

interface
type
TCifrado=class(TObject)
public
function C_xor(cadena:string):string;
function Rotn(cadena:string; N:integer):string;
function Reverse(cadena:string):String;


end;


implementation



{ TCifrado }

function TCifrado.C_xor(cadena: string): string;
var i:integer;
sfinal:string;
begin
sfinal:='';
for i :=1 to length(cadena) do
begin
sfinal:=sfinal+chr(ord(cadena[i]) xor length(cadena));
end;

SetLength(result, length(cadena));
result:=sfinal;
end;

function TCifrado.Reverse(cadena: string): String;
var
sfinal:String;
i:integer;
begin
sfinal:='';
for i:=length(cadena) downto 1 do
begin
sfinal:=sfinal+cadena[i];
end;

SetLength(result, length(cadena));
result:=sfinal;
end;

function TCifrado.Rotn(cadena: string; N: integer): string;
var
i:integer;
sfinal:string;
begin

for i :=1 to length(cadena) do
begin
sfinal:=sfinal+chr((ord(cadena[i])+N) mod 255 );
end;

SetLength(result, length(cadena));
result:=sfinal;
end;

end.


esta es la primera forma como explico
procedure TForm1.Button2Click(Sender: TObject);
begin
Cifrado:=TCifrado.Create;
try
if RadioButton1.Checked then
Memo2.Text:=Cifrado.Reverse(Memo1.Text)
else if RadioButton2.Checked then
Memo2.Text:=Cifrado.C_xor(Memo1.Text)
else if RadioButton3.Checked then
Memo2.Text:=Cifrado.Rotn(Memo1.Text,13);

finally
FreeAndNil(Cifrado);
end;

end;

esta es la segunda
procedure TForm1.Button2Click(Sender: TObject);
begin
if RadioButton1.Checked then
Memo2.Text:=Cifrado.Reverse(Memo1.Text)
else if RadioButton2.Checked then
Memo2.Text:=Cifrado.C_xor(Memo1.Text)
else if RadioButton3.Checked then
Memo2.Text:=Cifrado.Rotn(Memo1.Text,13);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Cifrado.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Cifrado:=TCifrado.Create;
end;

ecfisa
04-12-2014, 01:55:39
Hola BDWONG.

Si vas a usar uno o mas de los métodos de la clase varias veces durante la vida del form, considero mas práctico crear la instancia de clase en la creación del form y liberarla con él.

Pero si la vas a usar por única vez veo mejor liberarla al momento de no necesitarla mas, independientemente de la cantidad de sus métodos que utilices en ese momento.

De todos modos es sólo mi humilde opinión...

Saludos :)

mamcx
04-12-2014, 02:08:53
Estas en un lenguaje que no recolecta basura (en contraste con .NET, Java, etc), asi que guiate por:

Crea tan tarde como sea posible y libera tan pronto como sea posible

Ahora bien, es importante entender cual es el ciclo de vida de los objetos y como se relaciona eso con el manejo de la memoria y que es lo optimo para un computador.

Hay razones para desviarse de la idea general de "crea tarde/libera temprano". Sin embargo, el error de gente novata es preocuparse por la "eficiencia/velocidad", cuando es MUCHO mejor preocuparse por hacer las cosas simples y correctas. Si haces codigo simple y correcto, los compiladores modernos trabajaran de forma optima.

A proposito:

No tienes que hacer siempre un objeto. Delphi no es Java! Hacer funciones esta muy bien, y de hecho, es la forma MAS natural cuando tienes algo que es ENTRADA -> PROCESO -> SALIDA. Y te ahorras el tener que crear/destruir objetos y todo eso.

Delphi es muy versátil. Un montón de cosas se puede simplificar usando funciones/estructuras que reemplazan mucho codigo a punta de clases, y que puede ser mas legible y eficiente.

nlsgarcia
04-12-2014, 03:12:57
Mario,


...Delphi es muy versátil. Un montón de cosas se puede simplificar usando funciones/estructuras que reemplazan mucho código a punta de clases, y que puede ser mas legible y eficiente...
^\||/

Nelson.

BDWONG
04-12-2014, 04:53:55
Gracias por los consejos la verdad es que hay que veces que uno se mal acostumbra, como dice mamcx Delphi no es java y es cierto yo que vengo de este lenguaje aveces de manera inconsciente cargo conceptos los cuales no se pueden aplicar en todas partes por eso me gusto Delphi ya que no te obliga ha hacer las cosas solo de una forma si no que te da varias.

ecfisa pienso igual que tu XD

gracias por su ayuda chicos saludos.....

ecfisa
04-12-2014, 06:45:34
Hola BDWONG.

Yo creo que la respuesta mas directa a la pregunta ¿ Cuál es el mejor momento para liberar un objeto ? es: Cuando ya no precises usarlo.

Pero en la práctica hay situaciones en las que no se conocen a priori cuales, ni cuantas veces precisarás llamar a alguno de sus métodos. Si bién podrías crear/destruir el objeto las N-veces que precises usarlo, considero mas práctico y menos propenso a errores (por LOC), unificar la creación y liberación del objeto con la del formulario.

Por otro lado, si tu intención es encapsular varios métodos en una clase y esta sólo contiene métodos, nada te impide usarlos sin tener que crear una instancia de la misma, como podría hacerse en el caso de tu ejemplo:

...
type
TCifrado=class(TObject)
function C_xor(const Cadena: string): string;
function Reverse(const Cadena: string): string;
function Rotn(const Cadena: string; const N: Integer): string;
end;

implementation

{ TCifrado }

...

function TCifrado.C_xor(const Cadena: string): string;
var
i: Integer;
begin
Result:='';
for i:= 1 to Length(Cadena) do
Result:= Result + Chr(Ord(Cadena[i]) xor Length(Cadena));
end;
...


Uso:

procedure TForm1.Button1Click(Sender: TObject);
var
ci: TCifrado;
Cadena: string;
begin
Cadena:= 'Cadena de prueba';
Cadena:= ci.C_xor(Cadena);
ShowMessage(Cadena + ' / ' + ci.C_xor(Cadena));
end;


Saludos :)

Ñuño Martínez
04-12-2014, 14:10:15
Estas en un lenguaje que no recolecta basura (en contraste con .NET, Java, etc), asi que guiate por:

Crea tan tarde como sea posible y libera tan pronto como sea posible

Aun a riesgo de empezar un debate, en mi opinión es que esa guía vale tanto si no tienes recolector de basura como si sí lo tienes. No tengo experiencia con Java ni .Net, pero sí con PHP y JavaScript, y aunque sé que no todos los recolectores de basura son iguales y blablablah... finalmente decidí nunca confiar en ellos (http://bitacora.burdjia.com/por-que-no-confio-en-los-colectores-de-basuras/) y hacer la gestión de memoria de forma implícita.

A proposito:

No tienes que hacer siempre un objeto. Delphi no es Java! Hacer funciones esta muy bien, y de hecho, es la forma MAS natural cuando tienes algo que es ENTRADA -> PROCESO -> SALIDA. Y te ahorras el tener que crear/destruir objetos y todo eso.
Aquí te doy toda la razón. Además, usando el nombre de la unidad puedes usarlo como si fueran "objetos" aunque realmente no lo sean. Por ejemplo, puedes escribir "sysutils.ExtractFilePath (NombreArchivo)", como si "sysutils" fuera un objeto.

mamcx
04-12-2014, 16:17:24
Aun a riesgo de empezar un debate, en mi opinión es que esa guía vale tanto si no tienes recolector de basura como si sí lo tienes.


Es una buena idea en general, si ademas extendemos de memoria a recursos.


No tengo experiencia con Java ni .Net, pero sí con PHP y JavaScript, y aunque sé que no todos los recolectores de basura son iguales y blablablah... finalmente decidí nunca confiar en ellos (http://bitacora.burdjia.com/por-que-no-confio-en-los-colectores-de-basuras/) y hacer la gestión de memoria de forma implícita.


PHP & JavaScript. Pesimos lenguajes, pesimos recolectores. El de Java & .NET son todo otro cuento. La cantidad esfuerzo que se le ha metido para "domar" javascript es inmensa... si no fuera por las toneladas de $$$ e ingenieros que Apple, Google, Mozilla & MS le meten... Y algo parecido ocurre con PHP.

Pero no es bueno generalizar. Como todo, hay malas y buenas implementaciones.

P.D: Una idea muy interesante, que sin GC logra el objetivo a nivel mas general

http://blog.skylight.io/rust-means-never-having-to-close-a-socket/

BDWONG
05-12-2014, 00:04:44
Gracias ecfisa por tu respuesta, yo no sabia que se podían utilizar métodos de una clase si previamente haber creado un objeto, si me di cuenta pero pensé que era error de mi delphi :D

La verdad que no me siento nada cómodo con esta característica siento que para este ejemplo que estoy haciendo sera mas conveniente utilizar una unit común y corriente porque me da la impresión que crear un clase para jamas instanciar su objeto no seria realmente usar poo, ademas que sentiré que estoy haciendo que un problema relativamente sencillo se convierta en una revoltura de complicaciones.

Saludos......

ecfisa
05-12-2014, 03:36:26
Hola BDWONG
... yo no sabia que se podían utilizar métodos de una clase si previamente haber creado un objeto, si me di cuenta pero pensé que era error de mi delphi :D

La verdad que no me siento nada cómodo con esta característica siento que para este ejemplo que estoy haciendo sera mas conveniente utilizar una unit común y corriente ...
Estoy totalmente de acuerdo y disculpa si dí a entender que era mi consejo hacerlo de ese modo, no lo es en absoluto.

En este caso específico como comentas, no aporta beneficios. Mi intención era solo comentarte que si deseabas hacerlo, Delphi también lo permite.

Saludos :)

dec
05-12-2014, 09:41:29
Hola,

Entonces, que me quede claro, ¿se pueden usar métodos de una clase sin instanciarla y sin que dichos métodos estén declarados como "de clase"?

Este Delphi... :)

roman
05-12-2014, 18:03:28
Se puede pero no se debe...

Este ecfisa... :)

:D

// Saludos

mamcx
05-12-2014, 18:19:25
Y porque no?


Los class methods se usan regularmente de la forma exacta que se describe, no solo en Delphi sino en todos los lenguajes que soportan esta opcion.

nlsgarcia
05-12-2014, 20:29:06
David,


...¿se pueden usar métodos de una clase sin instanciarla y sin que dichos métodos estén declarados como "de clase"?...

:rolleyes:

Revisa este código:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Math;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

TC1 = Object
public
// Método y variable tipo Object
MsgUser : String;
function Calculate(N1, N2 : Double) : Double;
end;

TC2 = class
public
// Variable de Instancia
MsgUser : String;
// Método de Clase
class function Calculate1(N1, N2 : Double) : Double;
// Método de Instancia
function Calculate2(N1, N2 : Double) : Double;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

// Método Object
function TC1.Calculate(N1, N2: Double): Double;
begin
ShowMessage(Format('Calculate = %n (+,-,*,/) %n',[N1,N2]));
end;

// Método de Clase
class function TC2.Calculate1(N1, N2: Double): Double;
begin
ShowMessage(Format('Calculate = %n (+,-,*,/) %n',[N1,N2]));
end;

// Método de Instancia
function TC2.Calculate2(N1, N2: Double): Double;
begin
ShowMessage(Format('Calculate = %n (+,-,*,/) %n',[N1,N2]));
end;

// Uso del tipo Object y de Métodos de Clase y de Instancia
procedure TForm1.Button1Click(Sender: TObject);
var
C1 : TC1;
C2 : TC2;

begin

C1.MsgUser := 'Tipo Object = No requiere ser Instanciado para el uso de Variables y Métodos';
ShowMessage(C1.MsgUser);
C1.Calculate(7.1,3.14);

ShowMessage('Método de Clase = No requiere ser Instanciada la Clase para su uso');
TC2.Calculate1(7.1,3.14);

C2 := TC2.Create;
C2.MsgUser := 'Método y Variable de Instancia = Requiere ser Instanciada la Clase para su uso';
ShowMessage(C2.MsgUser);
C2.Calculate2(7.1,3.14);
C2.Free;

end;

end.

El código anterior en Delphi 7 sobre Windows 7 Professional x32, ejemplifica el uso del tipo Object y de Métodos de Clase y de Instancia.

Nota: El tipo object permite instanciar objetos sin usar el método Create y es muy util para implementaciones de tipos abstractos simples, para desarrollos formales orientados a objetos se debe usar el tipo Class.

Revisa esta información:

1- Objeto para Medir el Tiempo de Ejecución de un Proceso (http://www.clubdelphi.com/foros/showthread.php?t=85267)

2- Understanding Class Methods (http://delphi.about.com/od/objectpascalide/a/classmethods.htm)

Espero sea útil :)

Nelson.

ecfisa
05-12-2014, 21:17:43
Hola.

Agrego algo a lo expuesto por Nelson. El detalle es, que conviene abstenerse de incluir métodos virtuales cuando se usa el antiguo estilo Pascal de declaración,

type
xxx = object
procedure yyy; virtual;
end;

con las nuevas versiones de Delphi.

Eso trae aparejado problemas que ya han sido reportados en QualityCentral: Using old style Objects in D2009 fails (http://qc.embarcadero.com/wc/qcmain.aspx?d=71723)

Saludos :)

nlsgarcia
05-12-2014, 23:02:24
Daniel,


...conviene abstenerse de incluir métodos virtuales cuando se usa el antiguo estilo Pascal...trae aparejado problemas que ya han sido reportados en QualityCentral...

:rolleyes:

Revisa este código:


program testD2009;

{$APPTYPE CONSOLE}

uses
SysUtils;

Type
PObject1 = ^TObject1;
TObject1 = Object
FCount : Integer;
Constructor Init;
Procedure Add; virtual; { removing virtual allows the program to run }
end;

Type
PObject2 = ^TObject2;
TObject2 = Object(TObject1)
Constructor Init;
end;

Constructor TObject1.Init;
begin
{ Commenting out this assignment allows the program to run.
It also runs if Procedure Add; is not Virtual.
I presume there is some address mismatch resulting in an
over-write of the VMT }
FCount := 0;
Writeln('TDynArray:Init');
end;

Procedure TObject1.Add;
begin
Writeln('Add');
end;

Constructor TObject2.Init;
begin
Inherited Init;
Writeln('TObject2:Init');
end;

Var
Object1 : PObject1;
Object2 : PObject2;
begin
try
Object1 := New(PObject1,Init);
Object1^.Add;

Object2 := New(PObject2,Init);
Object2^.Add;
readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.

Tomado de : QualityCentral-Using old style Objects in D2009 fails (http://qc.embarcadero.com/wc/qcmain.aspx?d=71723)

El código anterior que falla en Delphi 2009 según se indica en QualityCentral, funciona correctamente en Delphi 2010 y Delphi XE6 sobre Windows x32 y Delphi XE7 sobre Windows 10 Technical Preview x32, al parecer el problema reportado solo aplica a Delphi 2009, no obstante para desarrollos formales orientados a objetos se debe usar el tipo Class.

Espero sea útil :)

Nelson.

ecfisa
06-12-2014, 00:14:32
Hola Nelson.
....al parecer el problema reportado solo aplica a Delphi 2009...
Bién por Embarcadero que lo haya solucionado en las versiones posteriores. Quede la advertencia para aquellos que usan la versión 2009 entonces... :)

Saludos :)

mamcx
06-12-2014, 20:10:25
No hay razon para decir que es "anormal" usar class methods. La idea de que solo es OO si se usan clases/objetos es solo un subproducto de que desafortunadamente la OO que se hizo popular es la deficiente implementación de C++/Java.

En ausencia de un sistema de modulos, los class methods se pueden usar tal como es usar funciones "simples". No hay razon para crear objetos para solo hacer un procesos que se puede directo con funciones/class-methods.

roman
06-12-2014, 21:03:54
Y porque no?


Los class methods se usan regularmente de la forma exacta que se describe, no solo en Delphi sino en todos los lenguajes que soportan esta opcion.

No hay razon para decir que es "anormal" usar class methods. La idea de que solo es OO si se usan clases/objetos es solo un subproducto de que desafortunadamente la OO que se hizo popular es la deficiente implementación de C++/Java.

En ausencia de un sistema de modulos, los class methods se pueden usar tal como es usar funciones "simples". No hay razon para crear objetos para solo hacer un procesos que se puede directo con funciones/class-methods.

Claro Mario, pero a lo que nos referimos dec y yo es a que en el ejemplo que puso, ecfisa olvidó poner class en la declaración de los métodos. Sirve si no se hace referencia a variables de la clase pero no es lo que "debe" hacerse.

No tenemos nada en contra de los métodos de clase :)

// Saludos

Al González
06-12-2014, 23:09:14
De hecho los métodos de clase están bastante difundidos ya en las bibliotecas Delphi nativas y de terceros. Cubren diversas necesidades. Menciono las que ahora vienen a mi memoria:


Agrupación de funciones y variables globales que llevan estrecha relación entre sí. Algo que ya puede hacer una mera unidad .pas, pero con las ventajas de la POO (el encapsulamiento, la herencia y el polimorfismo aplican también a clases sin instancias). Además de la obligación sintáctica de usar identificadores calificados (escribir el nombre de la clase) cuando se usa desde afuera.


Virtualización de funciones: A llama a B; en cierto caso deseo que llame a C en lugar de B, sin modificar su código. Para conseguir algo parecido sin clases había que definir a B como una variable procedimental, pero cambiar el valor de esta afectaba a todos los llamadores de A.


Una especie de patrón singleton, disponible desde que arranca el programa, sin necesidad de crear una instancia de la clase que lo implementa.


Exponer una variable global privada —o campo de clase—, como propiedad de sólo lectura, de tal manera que la variable no pueda ser modificada desde fuera de la clase, sólo leída. La manera de conseguir esto sin una clase era definiendo una función global que devolviera el valor de la variable, pero con el costo de la llamada (el Call interno) a la función —no hay Call alguno cuando una propiedad lee directamente de un campo FXXX—. El costo extra de CPU al usar una función puede aliviarse un poco si es compilada inline, pero esto no siempre es deseable o posible.


Que una clase pueda llevar el control de sus propias instancias. Los campos (variables) y métodos de clase pueden usarse para administrar una lista de todas las instancias de objeto de esa clase, e intercambiar mensajes entre ellas.


Un saludo.

Al González. :)

ecfisa
07-12-2014, 01:51:53
Hola roman.
Claro Mario, pero a lo que nos referimos dec y yo es a que en el ejemplo que puso, ecfisa olvidó poner class en la declaración de los métodos. Sirve si no se hace referencia a variables de la clase pero no es lo que "debe" hacerse.

No tenemos nada en contra de los métodos de clase :)

// Saludos
:) En realidad no fué un olvido, quise poner en relieve precisamente la curiosidad que Delphi permite utilizar "métodos de objeto" sin haber creado una instancia de la clase.

Saludos :)

BDWONG
07-12-2014, 02:31:02
ecfisa haber si entendi entoces un metodo de clase es una referencia encambio un metodo de objeto seria como llamar directamente a un metodo enconcreto

y por ultimo tu recomiendas el uso de alguno de los dos o dependiendo la ocacion ves si los utilizas

ecfisa
07-12-2014, 04:23:50
Hola BDWONG

Los métodos de clase se accionan sobre una referencia de clase y los métodos de objeto sobre una instancia de la clase, te pongo un código que ejemplifica a ambos:

...
type
TForm2 = class(TForm)
private
public
class procedure Mostrar(const aCaption: string); // método de clase
procedure foo; // método de objeto (o instancia)
end;

var
Form2: TForm2;

implementation

class procedure TForm2.Mostrar(const aCaption: string);
begin
if not Assigned(Form2) then
Form2:= TForm2.Create(nil);
Form2.Caption:= aCaption;
Form2.Show;
end;

procedure TForm2.foo;
var
x: Integer;
begin
x:= 5 + 4;
ShowMessage(IntToStr(x));
end;


Llamada ejemplo:

...
procedure TForm1.Button1Click(Sender: TObject);
begin
TForm2.Mostrar('Un título'); // método de clase, se invoca desde la clase
Form2.foo; // método de objeto, se invoca desde la instancia(objeto)
end;

También te podría interesar ampliar con estos artículos:

Understanding Class Methods (http://delphi.about.com/od/objectpascalide/a/classmethods.htm)
Methods (http://docwiki.embarcadero.com/RADStudio/XE6/en/Methods)
Delphi Class Methods (http://www.drbob42.com/examines/examin02.htm)


Saludos :)

Ñuño Martínez
07-12-2014, 14:50:41
No hay razon para decir que es "anormal" usar class methods. La idea de que solo es OO si se usan clases/objetos es solo un subproducto de que desafortunadamente la OO que se hizo popular es la deficiente implementación de C++/Java. Totalmente de acuerdo. De hecho, hay muy pocos lenguajes que, siendo absolutamente estrictos en la definición, sean orientados a objetos (Small-Talk y poco más).

Por cierto (aunque sé que llego tarde...), hay un método que usamos mucho sin crear el objeto: El método Create. ;)

Al González
08-12-2014, 05:35:09
Sí Ñuño, el constructor Create, y con la misma frecuencia el método de clase NewInstance. ;)

roman
10-12-2014, 21:48:47
:) En realidad no fué un olvido, quise poner en relieve precisamente la curiosidad que Delphi permite utilizar "métodos de objeto" sin haber creado una instancia de la clase.


De todas formas, no es lo correcto. Y los despistados, lean bien el hilo para saber que lo que se discute no es si los métodos de clase son buenos o no ;)

// Saludos

Eason
25-12-2014, 07:05:42
Si,los class methods se usan regularmente de la forma exacta que se describe.