‒ Encapsulación (Private, Strict private, Protected, Public)
La encapsulación nos permite organizar los atributos y métodos de una clase evitando el acceso a los mismos. Esto permite mantener la integridad y funcionamiento correcto de la clase cuando este es usado por otro programador. Sí dejamos que los atributos y métodos de una clase estén al alcance de todos, las acciones reciprocas que tendrán entre si los objetos serán muy engorrosos y a veces difícil de establecer.
Muchas veces la necesidad de evitar el acceso a los atributos y métodos de una clase se ha interpretado mal, como si estuviéramos ocultando información privilegiada que otros programadores no merecen conocer. Pero lo que se busca es reducir la complejidad en la reutilización de una clase.
La encapsulación se implementa en freepascal con secciones, usando las siguientes palabras reservadas: public, private, strict private, protected.
- Public.- Los atributos y métodos definidos aquí son accesibles por cualquier clase descendiente y que se encuentre en la unidad o en otra unidad, y también por los objetos que se crean con la clase. Cuando no se define ninguna sección en la clase entonces todos sus atributos y métodos pertenecen a la sección public.
- Private.- Los atributos y métodos definidos aquí son accesibles sólo por la misma clase y cualquier clase descendiente que se encuentre en la misma unidad, los objetos que se crean con la clase no tienen acceso a esta sección, a excepción de los que se encuentran en la misma unidad.
- Strict Private.- Los atributos y métodos definidos aquí son accesibles sólo por la clase misma. Ninguna clase descendiente podrá acceder a ellos, los objetos que se crean con la clase no tienen acceso a esta sección, sin importar si el objeto esta en la misma unidad.
- Protected.- Los atributos y métodos definidos aquí son accesibles sólo por la misma clase y cualquier clase descendiente que se encuentre en la misma unidad o en otra unidad, los objetos que se crean con la clase no tienen acceso a esta sección, a excepción de los que se encuentran en la misma unidad.
- Strict Protected.- Los atributos y métodos definidos aquí son accesibles sólo por la misma clase y cualquier clase descendiente que se encuentre en la misma unidad o en otra unidad, los objetos que se crean con esta clase no tienen acceso a esta sección, sin importar si el objeto esta en la misma unidad.
Pueden haber varias secciones en una clase, definidas en el orden que uno prefiere, pero dentro de cada sección primero se deben colocar los atributos y después los métodos.
La siguiente unidad y programa, es un ejemplo del uso de algunas de estas secciones.
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Unit UClase01;
Interface
Uses sysutils;
Type
TClase01=class
//cualquier clase descendiente y objeto tienen acceso
Constructor Crear(n:integer);
strict private
//ninguna clase descendiente y objeto tienen acceso
B01:integer;
protected
//cualquier clase descendiente tiene acceso incluso los que estan
// en otra unidad, los objetos no tienen acceso si estan en otra unidad.
Function Formato:string;
private
//cualquier clase descendiente que sólo este en la misma
//unidad tiene acceso, los objetos no tienen acceso si estan en otra unidad.
C01:integer;
public
//Se crea ObtenerB01 para que el método Formato de TClase02
//pueda acceder a B01 de modo indirecto.
Function ObtenerB01:integer;
Procedure Mostrar;
End;
TClase02=class(TClase01)
protected
Function Formato:string;
public
procedure Mostrar;
End;
implementation
Constructor TClase01.Crear(n:integer);
Begin
B01:=n;
C01:=n
End;
Function TClase01.Formato:string;
Begin
Formato:='Esta clase tiene = '+IntToStr(B01)+#13+#10+'C01 = '+IntToStr(C01)
End;
Function TClase01.ObtenerB01:integer;
Begin
ObtenerB01:=B01
End;
Procedure TClase01.Mostrar;
Begin
Writeln(Formato)
End;
Function TClase02.Formato:string;
//TClase02.Formato, puede acceder al campo C01 porque esta en private.
//Pero para acceder a B01 se debe usar el método ObtenerB01, porque
//B01 esta en strict private
//Si la clase TClase02 estuviera en otra unidad, entonces
//en la clase TClase01 se debe crear un método que nos permita
//acceder al campo C01.
Begin
Formato:='Esta otra clase tiene = '+IntToStr(ObtenerB01)+
#13+#10+'C01 = '+IntToStr(C01)
End;
Procedure TClase02.Mostrar;
Begin
Writeln(Formato);
End;
End.
Código fuente 13: Unidad Uclase01.pp con las clases TClase01 y TClase02.
Descargar
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Uses UClase01;
Var A:TClase01;
B:TClase02;
Begin
A:=TClase01.crear(10);
A.Mostrar;
B:=TClase02.crear(5);
B.Mostrar
End.
Código fuente 14: Programa que usa las clases TClase01 y TClase02.
Descargar
Cómo se puede observar, las clsaes TClase01 y TClase02, tienen el método llamado Formato, el método Formato de la clase TClase02, accede al campo B01 de la clase TClase01, a través del método ObtenerB01, esto es debido a que el campo B01 se encuentra en una sección Strict Private. Pero el campo C01 al encontrarse en una sección private, se puede acceder usando su nombre directamente.
Pero si la clase TClase02, se implementa en una unidad aparte, entonces se hará necesario crear un método que nos permite obtener el valor de C01, ya que los atributos y métodos de una sección private, sólo son accesibles si la clase se implementa en la misma unidad.
Continuando con el ejemplo de las clases TComplejo y TReal, procedemos a encapsular los atributos de la clase TComplejo como privados (private), pero haciendo un cambio en el método ObtCad de TReal, ya que este accede al atributo ParteReal directamente. A continuación las clases con los cambios correspondientes:
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Unit Complejos04;
Interface
Type
TComplejo = class
private
ParteReal,ParteImag:double;
public
Constructor Crear(i:double); //Crea un imaginario puro
Constructor Crear(r,i:double);
Function ObtReal:double;
Function ObtImag:double;
Procedure PonReal(n:double);
Procedure PonImag(n:double);
Function ObtCad(dec:integer):string;
Function PonCad(n:string):integer;
Procedure Adicion(n:TComplejo);
Procedure Multiplicacion(n:TComplejo);
End;
Implementation
Constructor TComplejo.Crear(i:double);
Begin
ParteReal:=0;
ParteImag:=i
End;
Constructor TComplejo.Crear(r,i:double);
Begin
ParteReal:=r;
ParteImag:=i;
End;
Function TComplejo.ObtReal:double;
Begin
ObtReal:=ParteReal
End;
Function TComplejo.ObtImag:double;
Begin
ObtImag:=ParteImag
End;
Procedure TComplejo.PonReal(n:double);
Begin
ParteReal:=n;
End;
Procedure TComplejo.PonImag(n:double);
Begin
ParteImag:=n
End;
Function TComplejo.ObtCad(dec:integer):string;
var aux1,aux2,p:string;
Begin
p:='';
Str(ParteReal:0:dec,aux1);
Str(ParteImag:0:dec,aux2);
if ParteImag>=0 then p:='+';
ObtCad := aux1 + p + aux2 + 'i';
End;
Function TComplejo.PonCad(n:string):integer;
Var aux:string;
p,i,error:integer;
PR,PI:string;
encontro:boolean;
Begin
aux:=n;
ParteReal:=0;
ParteImag:=0;
error:=0;
if (aux[length(aux)]='i') and (Not(aux[length(aux)-1]in['0'..'9']))
then aux:=Copy(aux,1,length(aux)-1)+'1i';
if aux[length(aux)]='i' then
Begin
delete(aux,length(aux),1);
if aux[length(aux)] in ['0'..'9']
then Begin
i:=length(aux);
encontro:=false;
p:=0;
while (not encontro) and (i>1) do
Begin
if (aux[i]='+') or (aux[i]='-')
then Begin
encontro:=true;
p:=i
end;
i:=i-1
End;
PR:=Copy(aux,1,p-1);
delete(aux,1,p-1);
PI:=aux;
Val(PR,ParteReal,error);
Val(PI,ParteImag,error);
if error<>0 then
Begin
ParteReal:=0;
ParteImag:=0
End
End;
End
else
Begin
Val(aux,ParteReal,error);
End;
PonCad:=error
End;
Procedure TComplejo.Adicion(n:TComplejo);
Begin
PonReal(ObtReal+n.ObtReal);
PonImag(ObtImag+n.ObtImag)
End;
Procedure TComplejo.Multiplicacion(n:TComplejo);
var PR,PI:double;
Begin
PR:=(ObtReal*n.ObtReal)-(ObtImag*n.ObtImag);
PI:=(ObtReal*n.ObtImag)+(ObtImag*n.ObtReal);
PonReal(PR);
PonImag(PI)
End;
End.
Código fuente 15: Clase TComplejo con secciones private y public.
Descargar
‒
Descargar
{$codepage utf8}
{$mode objfpc}
Unit Reales03;
Interface
Uses Complejos04;
Type
TReal = class(TComplejo)
Constructor Crear(r:double);
Function ObtCad(dec:integer):string;
End;
Implementation
Constructor TReal.Crear(r:double);
Begin
inherited Crear(r,0);
End;
Function TReal.ObtCad(dec:integer):string;
var p:string;
Begin
Str(ObtReal:0:dec,p);
ObtCad := p
End;
End.
Código fuente 16: Clase TReal con secciones private y public.
Descargar