Los campos y métodos de una clase pueden definirse de tipo public, protected y private, por defecto siempre son públicos.
Un método o campo público puede ser accedido desde fuera de la clase.
Una de las ventajas de la programación orientada a objetos es permitir encapsular datos y responsabilidades dentro de una clase.
Cuando uno planea una clase tiene que definir que quiero que se muestre hacia afuera y que quiero que quede oculto.
Normalmente los campos de una clase se definen dentro de la zona private o protected. Los métodos se definen públicos si queremos que sean accesibles desde fuera y privados o protegidos cuando solo quiero que puedan ser llamados desde la misma clase o subclase.
Si bien podemos definir todo público como venimos trabajando en los conceptos anteriores el agregado de estos modificadores nos permitirá crear clases más fáciles de reutilizar.
Resumiendo
Plantear una clase llamada TDado. Definir un campo llamado Valor y tres métodos uno privado que dibuje una línea de asteríscos y otro dos públicos, uno que genere un número aleatorio entre 1 y 6 y otro que lo imprima llamando en este último al que dibuja la línea de asteríscos.
Declarar la clase TDado en una unidad.
Luego de crear el proyecto138 procedemos a crear una unidad como ya vimos en conceptos anteriores:
unit Unit1; interface type TDado = class private Valor: Integer; procedure Separador; public procedure Tirar; procedure Imprimir; end; implementation procedure TDado.Separador; begin WriteLn('********************'); end; procedure TDado.Tirar; begin Valor := Random(6) + 1; end; procedure TDado.Imprimir; begin Separador; WriteLn(Valor); Separador; end; end.
program Proyecto138; {$APPTYPE CONSOLE} uses Unit1 in 'Unit1.pas'; var Dado1: TDado; begin Randomize; WriteLn('Prueba del dado'); Dado1 := TDado.Create; Dado1.Tirar; Dado1.Imprimir; Dado1.Free; ReadLn; end.
Disponemos de la palabra clave private para indicar que los campos y métodos siguientes solo se podrán acceder dentro de la misma clase:
TDado = class private Valor: Integer; procedure Separador;
Ahora si debemos disponer de la palabra clave public para identificar que métodos serán públicos:
public procedure Tirar; procedure Imprimir;
La codificación de los métodos en la zona de la implementation de la unidad no varía en nada a lo ya visto.
Ahora si hay que tener en cuenta que en el archivo Proyecto138.dpr donde definimos un objeto de la clase TDado solo tenemos acceso a los métodos públicos:
var Dado1: TDado; begin Randomize; WriteLn('Prueba del dado'); Dado1 := TDado.Create; Dado1.Tirar; Dado1.Imprimir; Dado1.Free;
Si intentamos acceder a un campo o método público se genera un error sintáctico:
Es decir que el objeto Dado1 solo puede llamar a los métodos Tirar e Imprimir que son los públicos.
Tiene grandes ventajas el encapsulamiento, como vemos al no poder asignar un valor al valor del dado desde fuera de la clase, luego si se genera un valor equivocado en el dado el problema se encuentra dentro de la clase TDado.
Lo más común es definir distintas unidades para cada clase, pero si codificamos la clase en el mismo archivo Proyecto138.dpr luego los objetos que definimos en ese archivo tienen acceso a los campos y métodos privados:
program Proyecto138; {$APPTYPE CONSOLE} type TDado = class private Valor: Integer; procedure Separador; public procedure Tirar; procedure Imprimir; end; procedure TDado.Separador; begin WriteLn('********************'); end; procedure TDado.Tirar; begin Valor := Random(6) + 1; end; procedure TDado.Imprimir; begin Separador; WriteLn(Valor); Separador; end; var Dado1: TDado; begin Randomize; WriteLn('Prueba del dado'); Dado1 := TDado.Create; Dado1.Valor := 5; Dado1.Imprimir; Dado1.Free; ReadLn; end.
Este programa no genera error ya que la clase TDado se encuentra definida en el mismo archivo donde definimos el objeto Dado1.
En las últimos versiones de Delphi se ha agregado el modificador strict private y strict protected para salvar las situaciones donde se definen objetos de dicha clase en el mismo archivo:
type TDado = class strict private Valor: Integer; procedure Separador; public procedure Tirar; procedure Imprimir; end;
Declarar una clase llamada TCalculadora que disponga de dos métodos para la carga de valores de tipo Double (almacenar los datos en dos campos)
Definir las responsabilidades de sumar, restar, multiplicar, dividir e imprimir.
Declarar luego una clase llamada TCalculadoraCientifica que herede de TCalculadora y añada las responsabilidades de calcular el cuadrado del primer número y la raíz cuadrada.
Declarar las dos clases en una unidad.
Definir los campos Valor1, Valor2 y Resultado en la zona protected de la clase.
unit Unit1; interface type TCalculadora = class protected Valor1: Double; Valor2: Double; Resultado: Double; public procedure Cargar1; procedure Cargar2; procedure Sumar; procedure Restar; procedure Multiplicar; procedure Dividir; procedure Imprimir(mensaje: String); end; TCalculadoraCientifica = class(TCalculadora) procedure Cuadrado; procedure Raiz; end; implementation procedure TCalculadora.Cargar1; begin Write('Ingrese valor:'); ReadLn(Valor1); end; procedure TCalculadora.Cargar2; begin Write('Ingrese valor:'); ReadLn(Valor2); end; procedure TCalculadora.Sumar; begin Resultado := Valor1 + Valor2; end; procedure TCalculadora.Restar; begin Resultado := Valor1 - Valor2 end; procedure TCalculadora.Multiplicar; begin Resultado := Valor1 * Valor2; end; procedure TCalculadora.Dividir; begin Resultado := Valor1 / Valor2; end; procedure TCalculadora.Imprimir(mensaje: String); begin WriteLn(mensaje,':', Resultado:0:2); end; procedure TCalculadoraCientifica.Cuadrado; begin Resultado := Valor1 * Valor1; end; procedure TCalculadoraCientifica.Raiz; begin Resultado := Sqrt(Valor1); end; end.
program Proyecto139; {$APPTYPE CONSOLE} uses Unit1 in 'Unit1.pas'; var Calculadora1: TCalculadora; CalculadoraCientifica1: TCalculadoraCientifica; begin WriteLn('Uso de la calculadora'); Calculadora1 := TCalculadora.Create; Calculadora1.Cargar1; Calculadora1.Cargar2; Calculadora1.Sumar; Calculadora1.Imprimir('Suma'); Calculadora1.Restar; Calculadora1.Imprimir('Resta'); Calculadora1.Multiplicar; Calculadora1.Imprimir('Multiplicación'); Calculadora1.Dividir; Calculadora1.Imprimir('Division'); Calculadora1.Free; WriteLn('Uso de la calculadora científica'); CalculadoraCientifica1 := TCalculadoraCientifica.Create; CalculadoraCientifica1.Cargar1; CalculadoraCientifica1.Cargar2; CalculadoraCientifica1.Sumar; CalculadoraCientifica1.Imprimir('Suma'); CalculadoraCientifica1.Restar; CalculadoraCientifica1.Imprimir('Resta'); CalculadoraCientifica1.Multiplicar; CalculadoraCientifica1.Imprimir('Multiplicación'); CalculadoraCientifica1.Dividir; CalculadoraCientifica1.Imprimir('Division'); CalculadoraCientifica1.Cuadrado; CalculadoraCientifica1.Imprimir('Cuadrado del primer valor'); CalculadoraCientifica1.Raiz; CalculadoraCientifica1.Imprimir('Raiz del primer valor'); CalculadoraCientifica1.Free; ReadLn; end.
La clase TCalculadora define en la zona protected los tres campos para que puedan ser accedidos solo por la clase TCalculadora o cualquier sublclase:
TCalculadora = class protected Valor1: Double; Valor2: Double; Resultado: Double; public procedure Cargar1; procedure Cargar2; procedure Sumar; procedure Restar; procedure Multiplicar; procedure Dividir; procedure Imprimir(mensaje: String); end;
Los métodos de la clase TCalculadoraCientifica pueden acceder a los campos protected de la clase padre:
procedure TCalculadoraCientifica.Cuadrado; begin Resultado := Valor1 * Valor1; end;
Pero los objetos que se definan de la clase TCalculadora y TCalculadoraCientifica solo podrán acceder a los métodos públicos:
WriteLn('Uso de la calculadora'); Calculadora1 := TCalculadora.Create; Calculadora1.Valor1 := 100; // Error de compilación debido al intento de acceder a un campo protegido
Hay que tener en cuenta que no podemos definir Valor1, Valor2 y Resultado en la zona private ya que esto hará que la subclase TCalculadoraCientifica no tenga acceso a dichos campos.
unit Unit1; interface type TVector = array[1..5] of Integer; TNumerosAleatorios = class private Vector: TVector; procedure Cargar; public constructor Create; procedure Imprimir; procedure MostrarMayor; procedure MostrarMenor; end; implementation procedure TNumerosAleatorios.Cargar; var f: Integer; begin for f := 1 to 5 do Vector[f] := Random(10) + 1; end; constructor TNumerosAleatorios.Create; begin Cargar; end; procedure TNumerosAleatorios.Imprimir; var f: Integer; begin for f:=1 to 5 do Write(Vector[f],' '); WriteLn; end; procedure TNumerosAleatorios.MostrarMayor; var f: Integer; mayor: Integer; begin mayor := Vector[1]; for f:=2 to 5 do if Vector[f] > mayor then mayor := Vector[f]; WriteLn('El elemento mayor del vector es:', mayor); end; procedure TNumerosAleatorios.MostrarMenor; var f: Integer; menor: Integer; begin menor := Vector[1]; for f:=2 to 5 do if Vector[f] < menor then menor := Vector[f]; WriteLn('El elemento menor del vector es:', menor); end; end. program Proyecto140; {$APPTYPE CONSOLE} uses Unit1 in 'Unit1.pas'; var NumerosAleatorios1: TNumerosAleatorios; begin Randomize; NumerosAleatorios1 := TNumerosAleatorios.Create; NumerosAleatorios1.Imprimir; NumerosAleatorios1.MostrarMayor; NumerosAleatorios1.MostrarMenor; NumerosAleatorios1.Free; ReadLn; end.