Sign in Join
Wiki copytemporary

Understanding Interfaces/es: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## La razón de las interfaces
22
33Las clases que extienden otras clases pueden llamarse sub-clases o clases derivadas. Por ejemplo, podría extenderse la clase `bicicleta` para tener una sub-clase `montañera`, y una sub-clase `paseo`. Estas clases heredan muchas de las funciones comunes de la clase `bicicleta`, pero añaden opciones únicas como la baca para la de `paseo`. Puedes llamar métodos de `bicicleta`, sabiendo que se aplican generalmente a todos los tipos de bicicleta.
44
55Este es un uso tradicional y estándar para las clases, dado que las sub-clases son solamente variaciones sobre un tema. Pero suponiendo que hubiera una aplicación donde existieran objetos de clase bicicleta, de automóviles, de lavacoches y otros, y en dicha aplicación se quisiera que cada clase tuviera el siguiente método:
66
77``` pascal
88function EsReciclable : Boolean;
99```
1010
1111Esto permitiría saber si el objeto contiene materiales reciclables. Se podría definir una clase de alto nivel que contuviera este método, y definir todas las clases derivadas de ella. O simplemente podrías agregar el método a cada sub-clase. O podrían usarse *interfaces*. Las interfaces simplemente pondrían orden en esta situación. Definiendo una interfaz que agrupe estos métodos juntos, establece una norma para todas las clases que implementen la interfaz. Hacen más fácil que el programador se discipline en desarrollar la aplicación; todas las clases tienen un conjunto de métodos que son idénticos y el compilador insiste que todos los métodos en una interfaz se implementen.
1212
1313Regresando al escenario del objeto reciclable, cada sub-clase hereda funciones comunes de su clase padre en particular. Esto describe la estructura básica de la sub-clase. También hereda (por implementación) las funciones comunes que se extienden por todas las clases.
1414
1515## Ejemplo de interfaz
1616
1717Como muchas ideas, un ejemplo es la mejor forma de ilustrar los conceptos. Lo haremos por etapas para que las cosas sean tan simples como sea posible. Primero, definamos una clase automóvil:
1818
1919``` pascal
2020type
2121(* Definimos nuestra clase Automóvil. *)
2222 TAutomovil = class
2323 private
2424 fMarca: String;
2525 fEdad: Byte;
2626 public
2727 (* Constructor del Automóvil. *)
2828 constructor Create (aMarca: String);
2929 published
3030 (* Propiedades del Automóvil. *)
3131 property Marca: String read fMarca;
3232 property Edad: Byte read fEdad write fEdad;
3333 end;
3434```
3535
3636Esta clase se define por defecto basado en [[TObject]] dado que no especificamos el tipo de clase base. Esta clase tiene dos propiedades, y un constructor, que se muestran aquí:
3737
3838``` pascal
3939(* Constructor de la implementación para la clase Automóvil. *)
4040 constructor TAutomovil.Create (aMarca : String);
4141 begin
4242 (* Guarda el marca del automóvil y pone la edad por defecto. *)
4343 fMarca := aMarca;
4444 fEdad := 0
4545 end;
4646```
4747
4848Aquí asignamos las dos propiedades del automóvil: su marca y edad. La marca se pasa como parámetro y asignamos una edad por defecto de 0. Ahora definiremos otra clase – una clase bicicleta:
4949
5050``` pascal
5151type
5252(* Definimos nuestra clase Bicicleta. *)
5353 TBicicleta = class
5454 private
5555 fFemenina: Boolean;
5656 fEdad: Byte;
5757 public
5858 (* Constructor de la Bicicleta. *)
5959 constructor Create (aFemenina: Boolean; aEdad: Byte);
6060 published
6161 (* Propiedades de la Bicicleta. *)
6262 property esFemenina: Boolean read fFemenina;
6363 property Edad: Byte read fEdad write fEdad;
6464 end;
6565```
6666
6767Esta clase tiene dos propiedades y un constructor como aquí se muestra:
6868
6969``` pascal
7070(* Constructor de la implementación para la clase bicicleta. *)
7171 constructor TBicicleta.Create (aFemenina: Boolean; aEdad: Byte);
7272 begin
7373 (* Save the passed parameters. *)
7474 fFemenina := aFemenina;
7575 fEdad := aEdad
7676 end;
7777```
7878
7979Esta clase es un poco distinta de la clase automóvil, lo suficiente para ver que podríamos no haber basado el automóvil en la bicicleta o la bicicleta en el automóvil. Ahora definiremos una interfaz que diga si un clase de objeto es reciclable:
8080
8181``` pascal
8282 type
8383 (* Una definición de interfaz. *)
8484 IReciclable = Interface (IInterface)
8585 (* Una sola función que da soporte a la propiedad. *)
8686 function MaterialEsReciclable: Boolean;
8787 (* Una sola propiedad. *)
8888 property esReciclable: Boolean read MaterialEsReciclable;
8989 end;
9090```
9191
9292Nuestra interfaz usa la definición estándar IInterface como base. Las definiciones de interfaces son como definiciones de clase con todos los elementos abstractos, así que no tenemos que declararlos como abstractos – lo son por defecto.
9393
9494Esta interfaz añade una propiedad esReciclable a cada clase que la implemente. Para cada clase que la implemente se garantizará que tendrá exactamente la misma forma de preguntar si es reciclable. Este es el poder y el beneficio de las interfaces – uniformidad a través de clases potencialmente muy distintas.
9595
9696Cualquier clase puede implementar tantas interfaces como se quiera – puede conformar cualquier estándar global en efecto. Nótese que debemos definir la propiedad usando una función – no podemos declarar un campo de datos `Boolean` en la interrfaz dado que las interfaces no contienen datos.
9797
9898Ahora cambiemos nuestras clases para que den soporte a esta definición de interfaz:
9999
100100``` pascal
101101 type
102102 (* Definimos nuestra clase Automóvil. *)
103103 TAutomovil = class (TInterfacedObject, IReciclable)
104104 private
105105 fMarca: String;
106106 fEdad: Byte;
107107 fEsReciclable: Boolean; { Añadido para dar soporte a IReciclable. }
108108 function MaterialEsReciclable: Boolean; { Añadido para IReciclable. }
109109 public
110110 (* Constructor del Automóvil. *)
111111 constructor Create (aMarca: String);
112112 published
113113 (* Propiedades del Automóvil. *)
114114 property Marca: String read fMarca;
115115 property Edad: Byte read fEdad write fEdad;
116116 (* Añadido para IReciclable. *)
117117 property esReciclable: Boolean read MaterialEsReciclable;
118118 end;
119119```
120120
121121Nótese que pusimos la función usada por la propiedad de interfaz `esReciclable` en la sección privada (`private`) – queremos que la propiedad la use sólo quien la llame.
122122
123123\[Nota del autor: cuando se compila, el compilador insiste en la presencia de la función `MaterialEsReciclable`, pero no en la parte más importante – la propiedad. Así como lo puede ver el autor, esto no obliga la opción predominante de la interfaz – ¡la propiedad!\]
124124
125125Ahora hemos basado nuestra clase en la clase [[TInterfaceObject]], la cual provee de algo de soporte estándar para las clases que implementan interfaces. Y hemos también basado nuestra clase en `IReciclable`, nuestra nueva interfaz.
126126
127127Pero también debemos declarar la nueva función `MaterialEsReciclable`:
128128
129129``` pascal
130130(* Función del automóvil requerida por el atributo EsReciclable. *)
131131 function TAutomovil.MaterialEsReciclable: Boolean;
132132 begin
133133 Result := fEsReciclable
134134 end;
135135```
136136
137137Y no debemos olvidar asignar este valor reciclable. Lo haremos diréctamente aquí en el constructor:
138138
139139``` pascal
140140(* Constructor para la clase automóvil. *)
141141 constructor TAutomovil.Create (aMarca: String);
142142 begin
143143 (* Guarda la marca del automóvil y asigna una edad por defecto. *)
144144 fMarca := aMarca;
145145 fEdad := 0;
146146 fEsReciclable := true { Asigna que es reciclable. }
147147 end;
148148```
149149
150150¡Vaya! Pero debemos hacer lo mismo para la clase `Bicicleta` para mostrar el auténtico efecto. Veremos el código completo para definir y usar estas clases, las cuales puedes copiar y pegar en el *Editor de Código*:
151151
152152``` pascal
153153unit Unit1;
154154
155155{$mode objfpc}{$H+}
156156
157157interface
158158
159159 uses
160160 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;
161161
162162 type
163163 (* Una definición de interfaz. *)
164164 IReciclable = Interface (IInterface)
165165 (* Una sola función que da soporte a la propiedad. *)
166166 function MaterialEsReciclable: Boolean;
167167 (* Una sola propiedad. *)
168168 property esReciclable: Boolean read MaterialEsReciclable;
169169 end;
170170
171171 (* Definimos nuestra clase Automóvil. *)
172172 TAutomovil = class (TInterfacedObject, IReciclable)
173173 private
174174 fMarca: String;
175175 fEdad: Byte;
176176 fEsReciclable: Boolean; { Añadido para dar soporte a IReciclable. }
177177 function MaterialEsReciclable: Boolean; { Añadido para IReciclable. }
178178 public
179179 (* Constructor del Automóvil. *)
180180 constructor Create (aMarca: String);
181181 published
182182 (* Propiedades del Automóvil. *)
183183 property Marca: String read fMarca;
184184 property Edad: Byte read fEdad write fEdad;
185185 (* Añadido para IReciclable. *)
186186 property esReciclable: Boolean read MaterialEsReciclable;
187187 end;
188188
189189 (* Definimos nuestra clase Bicicleta. *)
190190 TBicicleta = class (TInterfacedObject, IReciclable)
191191 private
192192 fFemenina: Boolean;
193193 fEdad: Byte;
194194 function MaterialEsReciclable: Boolean; { Añadido para IReciclable. }
195195 public
196196 (* Constructor de la Bicicleta. *)
197197 constructor Create (aFemenina: Boolean; aEdad: Byte);
198198 published
199199 (* Propiedades de la Bicicleta. *)
200200 property esFemenina: Boolean read fFemenina;
201201 property Edad: Byte read fEdad write fEdad;
202202 (* Añadido para IReciclable. *)
203203 property esReciclable: Boolean read MaterialEsReciclable;
204204 end;
205205
206206{ TForm1 }
207207 TForm1 = class (TForm)
208208 procedure FormCreate (Sender: TObject);
209209 private
210210 { private declarations }
211211 public
212212 { public declarations }
213213 end;
214214
215215 var
216216 Form1: TForm1;
217217
218218implementation
219219
220220{$R *.frm}
221221
222222{ TForm1 }
223223
224224 procedure TForm1.FormCreate (Sender: TObject);
225225 var
226226 biciMama: TBicicleta;
227227 cochePapa: TAutomovil;
228228 begin
229229 { Instancia los objetos bicicleta y automóvil. }
230230 biciMama := TBicicleta.Create (true, 36);
231231 cochePapa := TAutomovil.Create ('Toyota Hilux');
232232 { Pregunta a cada si cada uno si es reciclable. }
233233 if cochePapa.esReciclable then
234234 ShowMessage ('El coche de papá es reciclable.')
235235 else
236236 ShowMessage ('El coche de papá no es reciclable.');
237237 if biciMama.esReciclable then
238238 ShowMessage ('La bici de mamá es reciclable.')
239239 else
240240 ShowMessage ('La bici de mamá no es reciclable.')
241241 end;
242242
243243(* Constructor para la clase automóvil. *)
244244 constructor TAutomovil.Create (aMarca: String);
245245 begin
246246 (* Guarda la marca del automóvil y asigna una edad por defecto. *)
247247 fMarca := aMarca;
248248 fEdad := 0;
249249 fEsReciclable := true { Asigna que es reciclable. }
250250 end;
251251
252252(* Función del Automóvil requerida para el atributo esReciclable. *)
253253 function TAutomovil.MaterialEsReciclable: Boolean;
254254 begin
255255 Result := fEsReciclable
256256 end;
257257
258258(* Constructor de la implementación para la clase bicicleta. *)
259259 constructor TBicicleta.Create (aFemenina: Boolean; aEdad: Byte);
260260 begin
261261 (* Save the passed parameters. *)
262262 fFemenina := aFemenina;
263263 fEdad := aEdad
264264 end;
265265
266266(* Función de la Bicicleta requerida para el atributo esReciclable. *)
267267 function TBicicleta.MaterialEsReciclable: Boolean;
268268 begin
269269 { Vamos a presuponer que sólo las bicibletas para hombre son reciclables. }
270270 Result := not self.esFemenina
271271 end;
272272
273273end.
274274```
275275
276276Al ejecutar... [[ShowMessage]] muestra lo siguiente:
277277
278-`El coche de papá es reciclable.`\
279-`La bici de mamá no es reciclable.`
278+```text
279+El coche de papá es reciclable.
280+La bici de mamá no es reciclable.
281+```
280282
281283Este post fue tomado de un artículo de internet que me pareció bien interesante para modificar y entender las interfaces. Siempre ha sido un tema tabú(?) preguntar y cuando se usan, puede darle más claridad a tu código.
282284
283285## Ver también
284286
285287- [[Accessing the Interfaces directly]]
286288- [[How To Use Interfaces]]
287289- [[Interfaces]]
288290
289291---
290292*From the Free Pascal wiki, page "Understanding Interfaces/es", as it stood on 2020-03-15 after a change by Ñuño Martínez, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history