Programación orientada a objetos
Contenido
- Introducción
- Conocimiento previo
- Referencias
- Índice
- 1. Introducción a la Programación Orientada a Objetos
- 1.1. ¿Por qué surge la POO?
- 1.2. Principios
- 2. Componentes de la POO
- 2.1. Clases y objetos
- 2.2. Atributos (propiedades) y estados
- 2.3. Métodos
- 2.3.1. Métodos de acceso o propiedades
- Getters
- Setters
- 2.3.1. Constructores y destructores
- 3. Encapsulación y visibilidad
- 7. Relaciones entre clases
- 8. Herencia
- 9. Polimorfismo
- 10. Diagrama de clases
- 11. Ejercicios
Conceptos fundamentales de la programación orientada a objetos: clases, objetos, atributos, métodos, encapsulación, herencia, polimorfismo y relaciones entre clases.
Introducción
La programación orientada a objetos (POO) es un paradigma de programación que organiza el código alrededor de objetos. Un objeto agrupa datos y comportamientos relacionados, de forma parecida a como pensamos en entidades del mundo real: una cuenta bancaria, un coche, un usuario, un producto o una partida de un videojuego.
Este enfoque ayuda a construir programas más organizados, reutilizables y fáciles de mantener. En lugar de trabajar únicamente con variables y funciones aisladas, la POO propone modelar el problema mediante clases, objetos, atributos, métodos y relaciones.
Conocimiento previo
Referencias
- Oracle Java Tutorials - Object-Oriented Programming Concepts
- Wikipedia - Programación orientada a objetos
- Booch, G., Maksimchuk, R. A., Engle, M. W., Young, B. J., Conallen, J. & Houston, K. A. (2007). Object-Oriented Analysis and Design with Applications. Addison-Wesley.
Índice
- Introducción a la Programación Orientada a Objetos 1.1. ¿Por qué surge la POO? 1.2. Principios
- Componentes de la POO 2.1. Clases y objetos 2.2. Atributos (propiedades) y estados 2.3. Métodos 2.3.1. Métodos de acceso o propiedades 2.3.2. Constructores y destructores
- Encapsulación y visibilidad
- Relaciones entre clases
- Herencia
- Polimorfismo
- Diagrama de clases
- Ejercicios
1. Introducción a la Programación Orientada a Objetos
La Programación Orientada a Objetos (abreviada como POO) es un paradigma de programación que cambia la forma en que pensamos y diseñamos el software.
Mientras que en la programación estructurada el foco está en las funciones y los procedimientos, en la POO el centro son los objetos, es decir, entidades que combinan datos y comportamiento en una sola unidad.
Podemos decir que la POO nos permite modelar problemas del mundo real de forma más intuitiva, representando cosas como usuarios, productos, vehículos, personajes de un videojuego o cuentas bancarias directamente en el código. Cada uno de estos elementos se convierte en un objeto, con sus propios atributos y acciones posibles.
1.1. ¿Por qué surge la POO?
Imagina un programa muy grande desarrollado únicamente con procedimiento, funciones y variables globales. Conforme el sistema crece, se vuelve cada vez más difícil de entender, mantener y ampliar. Los cambios en una parte del código pueden afectar a otras sin que nos demos cuenta, generando errores difíciles de localizar.
En los años 70 y 80, los programadores comenzaron a buscar formas de estructurar el código de manera más modular, para poder dividir un sistema complejo en pequeñas partes independientes y reutilizables. Así es como surge la Programación Orientada a Objetos, que permite construir software basado en unidades más cercanas a cómo pensamos en la vida real: objetos con propiedades y comportamientos propios.
El primer lenguaje que implementó conceptos orientados a objetos fue Simula 67, diseñado en los años 60 para simular entornos del mundo real. Más adelante, en los años 80, el lenguaje Smalltalk llevó la POO al siguiente nivel, y poco después se popularizaron otros como C++, Java y Python, que adoptaron estos conceptos y los hicieron accesibles a millones de programadores.
- Organización: el código se agrupa por responsabilidades.
- Reutilización: Se pueden crear objetos y clases reutilizables en diferentes proyectos.
- Mantenimiento: Los cambios afectan sólo a los objetos relacionados.
- Escalabilidad: facilita ampliar programas grandes sin perder estructura.
- Modularidad: Es más sencillo dividir un sistema en partes independientes.
- Mejor comprensión del problema: El código refleja la estructura del problema real.
💡 Ejemplo
Si piensas en un videojuego de coches, cada vehículo tiene unas propiedades que son comunes (Marca, Modelo, etc.), ahora bien sus valores cambian. Tal y como hemos aprendido ahora, necesitariamos bastantes variables para representar estas propiedades.
Inicio Definir marcaCoche1, marcaCoche2 como Cadena; Definir velocidadMaxCoche1, velocidadMaxCoche2 como Real;
marcaCoche1 ← "Toyota"; velocidadMaxCoche1 ← 180;
marcaCoche2 ← "Renault"; velocidadMaxCoche2 ← 160;FinImagina que hay que hacer esto para 1.000 coches o que queremos incluir nuevas propiedades, como el color, modelo, etc..
Con la POO, cada coche es un objeto, y el código se organiza de una manera más natural:
Inicio Definir coche1, coche2 como Coche;
coche1 ← ("Toyota",180); coche2 ← ("Renault",160);FinDe esta forma, el programa es más ordenado, más fácil de mantener y más fácil de entender.
Por lo tanto, cada objeto tiene:
- Datos, que describen su estado.
- Comportamientos, que representan las acciones que puede realizar.
1.2. Principios
La POO se basa en un conjunto de características fundamentales que definen su forma de trabajar.
- Encapsulación: proteger los datos de un objeto para que no puedan ser modificados directamente desde fuera.
- Abstracción: simplificar la realidad mostrando sólo lo esencial y ocultando los detalles que no son importantes para el usuario.
- Herencia: crear un objeto nuevo a partir de otro existente, reutilizando su código y ampliándolo.
- Polimorfismo: un mismo método puede comportarse de diferentes formas según el objeto que lo use.
Estos principios pueden ser dificiles de entender por primera vez. Más adelante se explicaran con mayor detalle.
2. Componentes de la POO
En la Programación Orientada a Objetos, el código se organiza a través de componentes principales que permiten construir y estructurar los programas.
Estos componentes son los bloques básicos con los que se modelan las entidades del mundo real dentro del software.
2.1. Clases y objetos
Una clase es como un molde o una plantilla que define cómo serán los objetos que se creen a partir de ella.
Dentro de una clase se describen:
- Los atributos (también llamados propiedades), que representan las características o datos del objeto.
- Los métodos, que son las acciones o comportamientos que ese objeto puede realizar.
Siguiendo el ejemplo del coche 🚗:
Imagina que quieres modelar un coche en un programa. La clase Coche podría tener:
- Atributos:
marca,modelo,color,velocidad. - Métodos:
acelerar(),frenar(),girar().
Clase Coche atributos: marca modelo color velocidad
métodos: acelerar() frenar() girar()Fin ClaseUn objeto es una instancia concreta de una clase. Es decir, cuando creas un objeto, estás creando un ejemplar real de esa clase.
Ejemplo:
Si tienes la clase Coche, puedes crear varios objetos:
miCoche→ marca: Toyota, modelo: CorollatuCoche→ marca: Ford, modelo: Focus
coche1 = Coche("Toyota", "Corolla")coche2 = Coche("Renault", "Clio")Cada objeto tiene sus propios datos, aunque comparten la misma estructura y comportamientos definidos en la clase.
2.2. Atributos (propiedades) y estados
Los atributos son los datos que describen un objeto. También se llaman propiedades o campos, dependiendo del lenguaje de programación. Son las variables que guardan información sobre el estado particular de cada objeto.
En un objeto Coche, algunos atributos podrían ser:
marcamodelocolorvelocidad
El conjunto de valores de sus atributos en un momento determinado se conoce como estado del objeto.
coche1.marca ← "Toyota"coche1.modelo ← "Corolla"coche1.color ← "Rojo"coche1.velocidad ← 0Estado de los objetos
Los atributos representan el estado del objeto en un momento dado. Si cambias los valores de los atributos, estás modificando el estado del objeto.
Por ejemplo, si aceleras el coche, el atributo velocidad cambia y por lo tanto cambia su estado.
Inicio miCoche.velocidad = 50Fin2.3. Métodos
Los metodos materializan las acciones que van a tener los objetos, es decir, es la forma en que se implementa un algoritmo que se aplica a todas las instancias de una clase, y si se desea, pueden utilizar los datos de los atributos que contiene cada objeto.
Ejemplo:
Clase Coche atributo velocidad
método acelerar(cantidad) velocidad ← velocidad + cantidad fin método
método frenar(cantidad) velocidad ← velocidad - cantidad fin métodoFin ClaseUn método puede comportarse como:
- Función. Cuando el algoritmo que contiene, al ser llamado, realiza una serie de instrucciones y por último devuelve un valor.
- Procedimiento. Cuando el algoritmo que contiene, al ser llamado, lleva a cabo una serie de acciones, pero en el resultado final no se espera que devuelva ningún valor.
Varios son los factores de los que depende que un método se implemente como procedimiento o como función. Primero, depende del lenguaje de programación utilizado, ya que algunos como Java solo utilizan funciones (no existen procedimientos como tal), y otros como Delphi distinguen entre funciones y procedimientos.
Los métodos pueden recibir parámetros o argumentos, que permiten enviar datos al algoritmo para que pueda realizar su funcionalidad. Estos parámetros se comportan como variables que solo sirven dentro del bloque del método.
Los parámetros o argumentos puede ser enviados al método de dos formas:
- Por valor -> Se crea una copia exacta de la información, una vez utilizada por el método, los datos del parámetro no se verán alterados.
- Por referencia -> Se envia una dirección de memoria dónde se encuentran los datos del parámetro, cuando se utiliza dentro del método los datos se verán afectados una vez finalizado.
2.3.1. Métodos de acceso o propiedades
Los métodos de acceso son operaciones que permiten consultar o modificar el valor de los atributos de un objeto de forma controlada. En lugar de acceder directamente a los datos internos de una clase, estos métodos actúan como intermediarios, garantizando que cualquier lectura o modificación se realice siguiendo las reglas definidas por la propia clase.
Tradicionalmente, los métodos encargados de obtener el valor de un atributo reciben el nombre de getters, mientras que los que permiten modificarlo se denominan setters.
Gracias a este mecanismo, la clase mantiene el control sobre su estado interno. Por ejemplo, un método setter puede comprobar que un valor sea válido antes de almacenarlo, evitando que el objeto quede en un estado inconsistente.
En algunos lenguajes de programación, como C#, Kotlin o Swift, estos métodos se presentan mediante propiedades. Desde el punto de vista del programador, una propiedad se utiliza como si fuera un atributo, aunque internamente ejecuta código para realizar la lectura o escritura del dato. Esto proporciona una sintaxis más sencilla sin renunciar al control sobre el acceso a la información.
De esta forma, los métodos de acceso y las propiedades permiten que el objeto controle su propio comportamiento. En lugar de modificar sus datos desde cualquier parte del programa, se utilizan operaciones definidas dentro de la propia clase para consultar o actualizar sus atributos.
Getters
Los getters son métodos cuyo objetivo es devolver el valor de un atributo. Normalmente no modifican el estado del objeto, sino que únicamente proporcionan acceso a la información cuando es necesario.
Por ejemplo, un objeto Persona podría disponer de un método getNombre() que devuelva el nombre almacenado en el atributo correspondiente.
Clase Persona atributo nombre
método getNombre() devolver nombre; fin métodoFin ClaseSetters
Los setters son métodos que permiten modificar el valor de un atributo. Antes de realizar el cambio, pueden comprobar que el nuevo valor cumpla determinadas condiciones.
Por ejemplo, un método setEdad() podría impedir que se asignen edades negativas o superiores a un determinado límite, garantizando así la coherencia de los datos del objeto.
Clase Persona atributo edad
método setEdad(nuevaEdad) Si nuevaEdad >= 0 Entonces edad ← nuevaEdad; Si no Escribir "Edad inválida"; Fin si fin métodoFin Clase2.3.1. Constructores y destructores
Un constructor es un método especial que se ejecuta cuando se crea un objeto. Su función principal es inicializar los atributos con valores adecuados.
Los métodos constructores se podrán identificar facilmente porque utilizan por defecto el mismo nombre de la clase.
Ejemplo:
Clase Coche atributo marca atributo modelo atributo velocidad
constructor Coche(marcaInicial, modeloInicial) marca ← marcaInicial modelo ← modeloInicial velocidad ← 0 fin constructorFin ClaseGracias al constructor, cada objeto empieza con un estado válido desde el momento en que se crea.
Cada clase puede contar con varios métodos constructores definidos dependiendo de la cantidad de parametros que reciba, aunque también puede suceder el caso de que no se defina ninguno. Que no se defina un método constructor, no significa que no exista; todas las clases cuentan por defecto con un método constructor que, al llamarse, inicializará a los valores por defecto los campos de dicha clase.
Algunos lenguajes también tienen destructores, que se ejecutan cuando un objeto deja de utilizarse. Gracias a esto, se puede liberar la memoria asignada a ese objeto.
En lenguajes de programación más modernos ya casi no se utilizá los destructores, ya que utilizan herramientas y mecanismos automáticos para realizar estas funciones. En los lenguajes de programación que no existan automatismos para destruir objetos, serán los programadores los responsables que deben utilizar los destructores en los momentos adecuados.
3. Encapsulación y visibilidad
La encapsulación consiste en proteger los datos internos de un objeto y controlar cómo se accede a ellos. Para conseguirlo, los atributos suelen declararse como privados y se proporcionan métodos públicos para consultar o modificar sus valores, tal y como se ha visto en el punto 2.3.1. Métodos de acceso o propiedades
La visibilidad determina la manera en que los miembros de una clase son accedidos desde otros puntos del programa. Es importante no solo para crear relaciones de herencia entre distintas clases, sino también para implementar los algoritmos.
La visibilidad se puede aplicar a nivel de los atributos, métodos, clases y la forma de estructurar el programa, en paquetes y librerías.
Distinguimos entre los siguientes tipos de visibilidad:
- Público (
+): accesible desde cualquier parte del programa. - Privado (
-): accesible solo desde la propia clase. - Protegido (
#): accesible desde la propia clase y aquellas clases que hereden de esta.
Existen tipos de lenguaje de programación que cuentan con algún tipo de visibilidad adicional.
Ejemplo:
Clase CuentaBancaria privado saldo
método ingresar(cantidad) si cantidad > 0 entonces saldo ← saldo + cantidad; fin si fin método
método consultarSaldo() devolver saldo; fin métodoFin ClaseEn este ejemplo, no se modifica el saldo directamente desde fuera. Se usa el método ingresar, que puede validar la operación antes de cambiar el estado del objeto.
7. Relaciones entre clases
En un programa orientado a objetos, suele haber más de una clase y estas no suelen estar aisladas, si no que en muchas casos colaboran entre sí mediante relaciones para compartir información.
Existen diferentes tipos de relaciones entre clases,
La asociación indica que una clase conoce o utiliza objetos de otra clase.
Ejemplo: un Profesor imparte una Asignatura.
La agregación representa una relación de tipo “tiene un”, pero las partes pueden existir de forma independiente.
Ejemplo: un Equipo tiene Jugadores, pero un jugador puede existir aunque el equipo desaparezca.
La composición es una relación más fuerte. Las partes dependen del objeto principal.
Ejemplo: un Pedido tiene LineasPedido; si se elimina el pedido, sus líneas dejan de tener sentido dentro del sistema.
8. Herencia
La herencia permite crear una clase nueva a partir de otra existente. La clase nueva hereda atributos y métodos de la clase base, y puede añadir o modificar comportamientos.
Ejemplo:
Clase Animal método respirar() Escribir "Respirando"; fin métodoFin Clase
Clase Perro hereda Animal método ladrar() Escribir "Guau"; fin métodoFin ClaseEn este caso, Perro hereda el método respirar de Animal y añade su propio método ladrar.
La herencia debe usarse cuando exista una relación clara de tipo “es un”. Por ejemplo, un perro es un animal. No conviene usar herencia solo para reutilizar código si la relación conceptual no es correcta.
9. Polimorfismo
El polimorfismo permite que una misma operación se comporte de forma diferente según el objeto que la ejecute.
Ejemplo:
Clase Animal método hacerSonido() Escribir "Sonido genérico"; fin métodoFin Clase
Clase Perro hereda Animal método hacerSonido() Escribir "Guau" fin métodoFin Clase
Clase Gato hereda Animal método hacerSonido() mostrar "Miau" fin métodoFin ClaseSi tenemos una lista de animales, podemos llamar a hacerSonido() sin preocuparnos de si el objeto concreto es un perro o un gato. Cada objeto responderá según su propia implementación.
10. Diagrama de clases
El diagrama de clases es un tipo de diagrama UML que representa la estructura de un sistema orientado a objetos. Muestra clases, atributos, métodos y relaciones entre clases.
Puedes ampliar la base de UML en el tutorial UML.
En un diagrama de clases, una clase suele representarse como un rectángulo dividido en tres partes:
+---------------------+| Coche |+---------------------+| - marca || - modelo || - velocidad |+---------------------+| + acelerar() || + frenar() |+---------------------+Los signos de visibilidad ayudan a identificar cómo se puede acceder a cada miembro:
+público-privado#protegido
Los diagramas de clases son útiles antes de programar porque permiten revisar el diseño y detectar responsabilidades mal repartidas o relaciones confusas.
11. Ejercicios
Ejercicio 1: Identificar clases y objetos
Piensa en una aplicación para gestionar una biblioteca. Propón tres clases y dos objetos concretos para cada una.
Ejercicio 2: Diseñar una clase
Diseña una clase Producto indicando al menos cuatro atributos y tres métodos, uno de ellos debe ser un constructor. Genera 2 objetos nuevo y explica qué estado tendrían.
Ejercicio 3: Encapsulación
Explica por qué no sería buena idea modificar directamente el saldo de una cuenta bancaria desde cualquier parte del programa. Muestra un ejemplo de cómo se podría implementar un método para ingresar dinero de forma segura.
Ejercicio 4: Herencia
Diseña una clase base Vehiculo y dos clases derivadas. Indica qué atributos o métodos compartirían y cuáles serían específicos.