enecumene, el 17 Mar 2017 - 6:53 PM, dijo:
Muchas gracias Agustín, sobre que me quede bien hasta la quinta vez al menos, estoy consciente de eso, de todos modos no es un proyecto prioritario, así que me tomaré mi tiempo, bien, entonces me recomiendas usar el record para paso de información y el uso de interface, la verdad no estoy empapado sobre éste último, pero si es la mejor manera, pues allá vamos, viendo tu ejemplo anterior, TPartido sería de la siguiente forma:
type
TPartido = record
Ganador: integer;
Perdedor: Integer;
WinnerAlias: String;
LoserAlias: String;
//...Más
end;
¿Es correcto?, viendo el ejemplo de interface, ¿cómo se instanciaría esa interface ó se crea?, asumo que es de la siguiente manera:
var unPartido: TPartido;
unRepo: IRepositorioPartidos;
begin
unPartido.Ganador := 'Fernando';
unPartido.Perdedor := 'Efren';
//...Más
//¿Se crea?
unRepo := IRepositorioPartidos.Create;
//ó Simplemente llamo al método
unRepo.Guardar(unPartido);
//¿?
unRepo.Free;
end;
Nop, como charlamos en este hilo (el cual te recomiendo que leas lo que pusimos Delphius y yo), las interfaces deben implementarse.
Una interfaz es un "tipo de datos", el cual solamente actua de protocolo. Osea, es ponerse de acuerdo en como se llaman los metodos, que parametros tienen, y de que tipo son. Por eso es que todo lo que define la interfaz es publico. Ademas las interfaces no tienen permitido definir variables de instancia, es decir, no tienen, a priori, estado, definen comportamiento puro. Esto no te exime de tener metodos "getters o setters", y en Delphi hasta podes tener propiedades. Otra cosa importante es que no se permite implementar ningun metodo, osea seria como que todos los metodos sean publicos, abstractos y virtuales; aun asi, una clase que implementa una interfaz tranquilamente puede poner los metodos como privados. Esto suelo hacerlo mucho ya que es una manera de "forzar" a utilizar la interfaz y no la implementacion
Tambien seria totalmente valido usar clases abstractas. Hay algunas diferencias, sintacticas, semanticas, y algunas cuestiones de cada lenguaje (pero ya es hilar muy fino). En sintesis las interfaces son "mas abstractas" que las clases abstractas, porque una clase abstracta se puede permitir tener variables de instancia y ademas implementar metodos si quisiera
Para poder usar una interfaz primero tenes que crear una implementacion. Implementar una interfaz significa crear una clase que implementa todos los metodos detallados en la interfaz. Esto es obligatorio. El compilador no te va a dejar tener una clase que no implemente todos los metodos de una interfaz
Asi declaras una interfaz
type
IMiInterfaz = interface
// en la vasta mayoria de los casos es muy util generar un guid
// esto lo haces poniendo el cursor justo debajo de la linea que le da el nombre
// a la interfaz y presionando Control+Shift+G. Te recomiendo que mires la ayuda de Delphi
// para aclararse para que es necesario este numero
procedure Ejecutar;
end;
Y asi declaras que implementas una interfaz
type
// una clase puede implementar mas de una interfaz si quisiera
TMiInterfaz = class(clase ancestro, interfazImplementada1, ..., interfazImplementadaN)
// se deben implentar todos los metodos de las interfaces que decimos que implementamos
end;
En Delphi, del mismo modo que todas las clases heredan, quierase o no, de TObject, las interfaces derivan todas de IInterface. Esta interfaz define 3 metodos, por lo tanto, siempre va a ser obligatorio implementar estos 3 metodos. Delphi provee algunas clases que implementan IInterface para ahorrarnos ese trabajo
Hay varias, pero por el momento, hay dos, quiza tres, que vale la pena mencionar
TInterfacedObject: esta clase esta definida en la undiad System y es una subclase de TObject que solamente implementa IInterface y nada mas. Basicamente realiza el conteo de referencias, es decir, la memoria se maneja "automaticamente" como los string y los record. El objeto se destruye solo cuando ninguna variable apunta a el. Con esto te ahorras los llamados a .Free
TComponent: que esta definido en System.Classes. Esta clase lo que hace es "desactivar" el conteo de referencias, e implementar otro esquema de memoria en la cual el "dueño" (owner) del componente se encarga de liberarlo. Por ejemplo todos los componentes y controles que estan en un Form, se destruyen cuando se destruye el Form. Si un componente no tiene su dueño, el responsable de liberarlo de memoria es el programador
TSingletonImplementation: definida en System.Generics.Defaults, esta tambien desactiva el conteo de referencias y es util para implementar justamente Singletons
Aca esta la ayuda de Delphi para el uso de interfaces: http://docwiki.embar...sing_Interfaces
El conteo de referencias, explicado bastante rapido y de manera practica, es mas o menos de esta manera. Cuando tenes una variable o campo, o mejor dicho una referencia a una interfaz, el compilador implicitamente hace algo de este estilo:
procedure AlgunProceso;
var
Interfaz: IInterface;
begin
// en este punto Interfaz = nil, osea, no hay una referencia a ninguna interfaz
Interfaz := TInterfacedObject.Create;
// al asignar el objeto, Interfaz es una referencia a una interfaz IInterface,
// y su contador de referencias es 1
end
En el momento que esa variable Interfaz, se va del "scope", esto quiere decir, cuando termina el procedimiento, o si la interfaz es una variable de instancia de la clase X, cuando la clase X es destruida, el conteo de referencias decrementa. Cuando llega a 0, el objeto se destruye solo
Ahora, si yo tuviera este codigo:
// programa principal
var
Intf: IInterface;
begin
Intf := TInterfacedObject.Create; // conteo de ref. 1
UsarInterfaz(Intf);
// termina el programa, la variable Intf "se va del alcance (scope)", por lo tanto
// se decrementa su conteo de ref. y pasa a 0, entonces se destruye
end;
procedure UsarInterfaz(Intf: IInterface);
begin
// cuando este procedimiento es invocado, el compilador pasa el parametro y en ese momento
// el conteo de referencias es 2
// trabajar con la interfaz
// fin del procedimiento. Cuando termina, se decrementa en 1 el conteo de referencias, es decir,
// el conteo de referencias es 1 y la interfaz "sigue viva"
end;
En resumen:
1. Defines la interfaz
2. Creas una clase que la implementa
3. Para usarla, instancias esa clase, pero cuando declaras el tipo de la variable, el chiste a todo esto es usar el tipo de la interfaz; no de la clase
Tu ejemplo seria:
var unPartido: TPartido;
unRepo: IRepositorioPartidos;
begin
unPartido.Ganador := 'Fernando';
unPartido.Perdedor := 'Efren';
//...Más
// cambie la I por una T, pero podria ser cualquier clase, siempre y cuando implemente
// IRepositorioPartidos. De no ser asi, se produce error de compilacion
unRepo := TRepositorioPartidos.Create;
unRepo.Guardar(unPartido);
end;