La programación orientada a objetos se basa en la declaración de clases; a diferencia de la programación estructurada, que está centrada en la definición de procedimientos y funciones.
Una clase es un molde del que luego se pueden crear múltiples objetos, con similares características.
Una clase es una plantilla (molde), que define campos o atributos (variables) y métodos (procedimientos y funciones)
La clase define los atributos y métodos comunes a los objetos de ese tipo, pero luego, cada objeto tendrá sus propios valores y compartirán las mismas funciones.
Debemos declarar una clase antes de poder crear objetos (instancias) de esa clase. Al crear un objeto de una clase, se dice que se crea una instancia de la clase o un objeto propiamente dicho.
La declaración de una clase, su implementación y la definición de un objeto la veremos mediante un ejemplo.
Confeccionar una clase que permita cargar el nombre y la edad de una persona. Mostrar los datos cargados. Imprimir un mensaje si es mayor de edad (edad>=18) o no
program Proyecto124; {$APPTYPE CONSOLE} type TPersona = class Nombre: String; Edad: Integer; procedure Cargar; procedure Imprimir; procedure EsMayorDeEdad; end; procedure TPersona.Cargar; begin Write('Ingrese el nombre de la persona:'); ReadLn(Nombre); Write('Ingrese la edad:'); ReadLn(Edad); end; procedure TPersona.Imprimir; begin WriteLn('Datos de la persona'); WriteLn('Nombre:', Nombre,' Edad:', Edad); end; procedure TPersona.EsMayorDeEdad; begin if Edad >= 18 then WriteLn('Es mayor de edad') else WriteLn('No es mayor de edad'); end; var Persona1: TPersona; begin Persona1 := TPersona.Create; Persona1.Cargar; Persona1.Imprimir; Persona1.EsMayorDeEdad; Persona1.Free; ReadLn; end.
La declaración de una clase es similar a la declaración de un registro, debemos definir los campos de la clase y dentro de la misma declarar los métodos (procedimientos y funciones) que acceden a los campos:
TPersona = class Nombre: String; Edad: Integer; procedure Cargar; procedure Imprimir; procedure EsMayorDeEdad; end;
La clase TPersona tiene dos campos llamados Nombre y Edad, y tres métodos llamados Cargar, Imprimir y EsMayorDeEdad.
Como vemos solo dentro de la estructura class declaramos los métodos, luego debemos implementarlos.
Para implementar los métodos debemos anteceder al nombre del método a que clase pertenece dicho método:
procedure TPersona.Cargar; begin Write('Ingrese el nombre de la persona:'); ReadLn(Nombre); Write('Ingrese la edad:'); ReadLn(Edad); end;
Los métodos tienen por objetivo cargar, consultar, modificar, imprimir etc. los campos.
En el método Imprimir se muestran los contenidos de los campos Nombre y Edad que fueron cargados en el método Cargar:
procedure TPersona.Imprimir; begin WriteLn('Datos de la persona'); WriteLn('Nombre:', Nombre,' Edad:', Edad); end;
Por último el método EsMayorDeEdad verifica el contenido del campo Edad y dependiendo de su contenido procedemos a mostrar si es mayor de edad o no:
procedure TPersona.EsMayorDeEdad; begin if Edad >= 18 then WriteLn('Es mayor de edad') else WriteLn('No es mayor de edad'); end;
Acotaciones: Un if en Delphi puede no llevar los bloques begin y end si en su interior hay una sola instrucción. Anteriormente no utilizamos esta característica para evitar errores (lo mismo se aplica para las estructuras repetitivas while y for).
El siguiente paso es definir un objeto de la clase TPersona en la zona de la var:
var Persona1: TPersona;
Para poder llamar a los métodos del objeto Persona1 debemos crear el objeto con la siguiente sintaxis:
Persona1 := TPersona.Create;
El método Create no lo hemos creado nosotros en la clase TPersona (veremos más adelante el concepto de herencia y como la clase TPersona hereda el método Create)
El método Create es el primero que debemos llamar y le antecedemos el nombre de la clase. Este método reserva espacio en la memoria para el almacenamiento del objeto Persona1 (si no lo llamamos luego se genera un error en tiempo de ejecución)
Una vez creado el objeto Persona1 podemos llamar a sus métodos antecediendo el nombre del objeto:
Persona1.Cargar; Persona1.Imprimir; Persona1.EsMayorDeEdad;
La ventaja de la programación orientada a objetos es poder encapsular campos y métodos dentro de una clase. Podemos luego declarar otra clase que tenga el mismo nombre de método "Imprimir" pero no habrá problemas porque se encuentra encapsulado dentro de una clase.
La POO (Programación Orientada a Objetos) presenta grandes beneficios cuando un programa es muy grande (decenas o cientos de miles de líneas)
La POO permite agrupar distintas funcionalidades y datos en distintas clases y facilitar su uso.
Otro punto fundamental en Delphi para trabajar con objetos es liberar el espacio de memoria cuando no necesitamos trabajar más con él llamando al método Free:
Persona1.Free;
El método Create es el primero que llamamos y el método Free es el último(al método Create lo llamamos antecediendo el nombre de la clase pero al método Free lo llamamos antecediendo el nombre del objeto)
Veremos luego que el método Free es heredado cuando declaramos una clase en Delphi.
Modificar el problema anterios para realizar la carga del nombre y la edad de dos personas. Mostrar los datos cargados. Imprimir un mensaje si son mayor de edad o no.
program Proyecto125; {$APPTYPE CONSOLE} type TPersona = class Nombre: String; Edad: Integer; procedure Cargar; procedure Imprimir; procedure EsMayorDeEdad; end; procedure TPersona.Cargar; begin Write('Ingrese el nombre de la persona:'); ReadLn(Nombre); Write('Ingrese la edad:'); ReadLn(Edad); end; procedure TPersona.Imprimir; begin WriteLn('Datos de la persona'); WriteLn('Nombre:', Nombre,' Edad:', Edad); end; procedure TPersona.EsMayorDeEdad; begin if Edad >= 18 then WriteLn('Es mayor de edad') else WriteLn('No es mayor de edad'); end; var Persona1: TPersona; Persona2: TPersona; begin Persona1 := TPersona.Create; WriteLn('Datos de la primer persona'); Persona1.Cargar; Persona2 := TPersona.Create; WriteLn('Datos de la segunda persona'); Persona2.Cargar; Persona1.Imprimir; Persona1.EsMayorDeEdad; Persona1.Free; Persona2.Imprimir; Persona2.EsMayorDeEdad; Persona2.Free; ReadLn; end.
Lo más importante es notar que básicamente lo único que cambia es la definición de dos objetos de la clase TPersona:
var Persona1: TPersona; Persona2: TPersona;
La clase no se ha modificado, solo la definición de dos objetos y las llamadas a los métodos respectivos de cada objeto (recordemos que una clase es un molde del cual podemos luego definir tantos objetos como sean necesarios)
Más adelante veremos que si codificamos un programa que sea una calculadora tendremos la clase "TBoton" y luego definiremos 19 objetos de la clase "TBoton".
Desarrollar un programa que cargue los lados de un triángulo e implemente los siguientes métodos: inicializar los campos, imprimir el valor del lado mayor y otro método que muestre si es equilátero o no.
program Proyecto126; {$APPTYPE CONSOLE} type TTriangulo = class Lado1: Integer; Lado2: Integer; Lado3: Integer; procedure Cargar; procedure LadoMayor; procedure EsEquilatero; end; procedure TTriangulo.Cargar; begin Write('Ingrese primer lado:'); ReadLn(Lado1); Write('Ingrese segundo lado:'); ReadLn(Lado2); Write('Ingrese tercer lado:'); ReadLn(Lado3); end; procedure TTriangulo.LadoMayor; begin Write('Lado mayor:'); if (Lado1 > Lado2) And (Lado1 > Lado2) then WriteLn(Lado1) else if Lado1 > Lado2 then WriteLn(Lado2) else WriteLn(Lado3); end; procedure TTriangulo.EsEquilatero; begin if (Lado1 = Lado2) and (Lado1 = Lado3) then WriteLn('Es un triangulo equilatero') else WriteLn('No es un triangulo equilatero'); end; var Triangulo1: TTriangulo; begin Triangulo1 := TTriangulo.Create; Triangulo1.Cargar; Triangulo1.LadoMayor; Triangulo1.EsEquilatero; Triangulo1.Free; ReadLn; end.
El nombre de la clase es TTriangulo (En Delphi la propuesta es que todos los tipos de datos empiecen con el caracter T) y requiere definir tres campos de tipo Integer donde almacenamos los valores de los lados del triángulo.
También declaramos la cabecera de los tres métodos requeridos para resolver el problema.:
type TTriangulo = class Lado1: Integer; Lado2: Integer; Lado3: Integer; procedure Cargar; procedure LadoMayor; procedure EsEquilatero; end;
Para implementar cada método debemos anteceder el nombre de la clase, dentro del método podemos acceder a todos los campos definidos en la clase directamente por su nombre:
procedure TTriangulo.Cargar; begin Write('Ingrese primer lado:'); ReadLn(Lado1); Write('Ingrese segundo lado:'); ReadLn(Lado2); Write('Ingrese tercer lado:'); ReadLn(Lado3); end;
El método LadoMayor muestra el valor mayor de los tres enteros ingresados por teclado en el método Cargar, es importante tener en cuenta que desde el bloque principal del programa primero debemos llamar a Cargar y luego a LadoMayor:
procedure TTriangulo.LadoMayor; begin Write('Lado mayor:'); if (Lado1 > Lado2) And (Lado1 > Lado2) then WriteLn(Lado1) else if Lado1 > Lado2 then WriteLn(Lado2) else WriteLn(Lado3); end;
El último método de esta clase verifica si los tres campos tienen almacenado un valor igual:
procedure TTriangulo.EsEquilatero; begin if (Lado1 = Lado2) and (Lado1 = Lado3) then WriteLn('Es un triangulo equilatero') else WriteLn('No es un triangulo equilatero'); end;
Previo al bloque principal begin end. definimos un objeto de la clase TTriangulo:
var Triangulo1: TTriangulo;
En el bloque principal creamos el objeto llamando al método Create antecediendo el nombre de la clase:
begin Triangulo1 := TTriangulo.Create;Seguidamente llamamos los métodos creados por nosotros en la clase TTriangulo:
Triangulo1.Cargar; Triangulo1.LadoMayor; Triangulo1.EsEquilatero;
Y finalmente ejecutamos el método Free para liberar espacio de memoria del objeto:
Triangulo1.Free; ReadLn; end.
Desarrollar una clase que represente un punto en el plano y tenga los siguientes métodos: cargar los valores de x e y, imprimir en que cuadrante se encuentra dicho punto (concepto matemático, primer cuadrante si x e y son positivas, si x<0 e y>0 segundo cuadrante, etc.)
program Proyecto127; {$APPTYPE CONSOLE} type TPunto = class X: Integer; Y: Integer; procedure Cargar; procedure ImprimirCuadrante; end; procedure TPunto.Cargar; begin Write('Ingrese coordenada x :'); ReadLn(X); Write('Ingrese coordenada y :'); ReadLn(Y); end; procedure TPunto.ImprimirCuadrante; begin if (X > 0) and (y > 0) then WriteLn('Se encuentra en el primer cuadrante.') else if (X < 0) and (Y > 0) then WriteLn('Se encuentra en el segundo cuadrante.') else if (X < 0) and (Y < 0) then WriteLn('Se encuentra en el tercer cuadrante.') else if (X > 0) and (Y < 0) then WriteLn('Se encuentra en el cuarto cuadrante.') else WriteLn('El punto no está en un cuadrante.'); end; var Punto1: TPunto; begin Punto1 := TPunto.Create; Punto1.Cargar; Punto1.ImprimirCuadrante; Punto1.Free; ReadLn; end.
A la clase la llamamos TPunto y en la declaración definimos dos campos y dos métodos:
TPunto = class X: Integer; Y: Integer; procedure Cargar; procedure ImprimirCuadrante; end;
El método Cargar pide ingresar por teclado las coordenadas x e y:
procedure TPunto.Cargar; begin Write('Ingrese coordenada x :'); ReadLn(X); Write('Ingrese coordenada y :'); ReadLn(Y); end;
El segundo método mediante un conjunto de if anidados verificamos en que cuadrante se encuentra el punto ingresado:
procedure TPunto.ImprimirCuadrante; begin if (X > 0) and (y > 0) then WriteLn('Se encuentra en el primer cuadrante.') else if (X < 0) and (Y > 0) then WriteLn('Se encuentra en el segundo cuadrante.') else if (X < 0) and (Y < 0) then WriteLn('Se encuentra en el tercer cuadrante.') else if (X > 0) and (Y < 0) then WriteLn('Se encuentra en el cuarto cuadrante.') else WriteLn('El punto no está en un cuadrante.'); end;
El bloque principal no tiene grandes diferencias con los problemas realizados anteriormente, definimos un objeto de la clase TPunto, creamos el objeto, llammamos a sus métodos y liberamos espacio del objeto:
var Punto1: TPunto; begin Punto1 := TPunto.Create; Punto1.Cargar; Punto1.ImprimirCuadrante; Punto1.Free; ReadLn; end.
program Proyecto128; {$APPTYPE CONSOLE} type TEmpleado = class Nombre: String; Sueldo: Double; procedure Cargar; procedure PagaImpuestos; end; procedure TEmpleado.Cargar; begin Write('Ingrese nombre:'); ReadLn(Nombre); Write('Ingrese sueldo:'); ReadLn(Sueldo); end; procedure TEmpleado.PagaImpuestos; begin if sueldo >= 3000 then WriteLn('Debe abonar impuestos') else WriteLn('No paga impuestos'); end; var Empleado1: TEmpleado; begin Empleado1 := TEmpleado.Create; Empleado1.Cargar; Empleado1.PagaImpuestos; Empleado1.Free; ReadLn; end. program Proyecto129; {$APPTYPE CONSOLE} type TOperacion = class valor1: Integer; valor2: Integer; procedure Cargar; procedure Sumar; procedure Restar; procedure Multiplicar; procedure Dividir; end; procedure TOperacion.Cargar; begin Write('Ingrese primer valor:'); ReadLn(valor1); Write('Ingrese segundo valor:'); ReadLn(valor2); end; procedure TOperacion.Sumar; var suma: Integer; begin suma := Valor1 + Valor2; WriteLn('La suma es:', suma); end; procedure TOperacion.Restar; var resta: Integer; begin resta := Valor1 - Valor2; WriteLn('La resta es:', resta); end; procedure TOperacion.Multiplicar; var multiplicacion: Integer; begin multiplicacion := Valor1 * Valor2; WriteLn('La multiplicación es:', multiplicacion); end; procedure TOperacion.Dividir; var division: Integer; begin division := Valor1 div Valor2; WriteLn('La división es:', division); end; var Operacion1: TOperacion; begin Operacion1 := TOperacion.Create; Operacion1.Cargar; Operacion1.Sumar; Operacion1.Restar; Operacion1.Multiplicar; Operacion1.Dividir; Operacion1.Free; ReadLn; end.