Objeto y clase

  • David García Solórzano

    Graduado Superior en Ingeniería en Multimedia e Ingeniero en Informática por la Universitat Ramon Llull desde 2007 y 2008, respectivamente. Es también Doctor por la Universitat Oberta de Catalunya desde 2013, donde realizó una tesis doctoral relacionada con el ámbito del e-learning. Desde 2008 es profesor de la Univesitat Oberta de Catalunya en los Estudios de Informática, Multimedia y Telecomunicación.

PID_00249622
Ninguna parte de esta publicación, incluido el diseño general y la cubierta, puede ser copiada, reproducida, almacenada o transmitida de ninguna forma, ni por ningún medio, sea éste eléctrico, químico, mecánico, óptico, grabación, fotocopia, o cualquier otro, sin la previa autorización escrita de los titulares del copyright.

Introducción

Este módulo tiene como objetivo principal explicar los elementos básicos de la programación orientada a objetos (POO). Concretamente, veremos qué es una clase y cuáles son los miembros de una clase –los atributos y métodos–, qué es un objeto, qué significa instanciar, qué son el estado y el comportamiento de un objeto, y qué es un mensaje.
Dentro de este módulo explicaremos, mediante diferentes ejemplos, cómo estos elementos se relacionan con el mundo real haciendo así más sencillo y natural el diseño de aplicaciones. Simultáneamente se introducirá el lenguaje de modelado de sistemas de software, UML (Unified Modeling Language). Concretamente, utilizaremos UML para representar gráficamente una clase de manera formal.

Objetivos

El objetivo principal de este módulo es introducir los conceptos básicos de la programación orientada a objetos (POO). Concretamente:
  1. Saber diferenciar entre un objeto y una clase, y comprender la relación que existe entre ellos.

  2. Conocer y entender las partes que componen una clase, es decir, los atributos y los métodos.

  3. Tener un primer contacto con el lenguaje de modelado UML.

  4. Saber los conceptos relacionados con un objeto, como son: instancia, estado, comportamiento y mensaje.

  5. Reflexionar sobre cómo el paradigma POO os anima e incluso os obliga, como programadores, a ver el mundo que os rodea de una manera diferente a como lo hacíais hasta ahora.

1.Definiendo los conceptos objeto y clase

1.1.¿Qué es un objeto?

Como ya habéis leído y os podías haber imaginado, el objeto es el elemento principal de la programación orientada a objetos y alrededor del cual gira este paradigma, de ahí el nombre.
En este punto lo más lógico sería preguntarse: ¿qué es un «objeto»?, ¿qué se entiende por «objeto» en la POO? Para responder a estas preguntas lo haremos de manera formal e informal. La formal nos lleva a la siguiente definición.
Un objeto en POO representa alguna entidad de la vida real, es decir, alguno de los objetos únicos que pertenecen al problema con el que nos estamos enfrentando, y con el que podemos interactuar.
Cada objeto, de igual modo que la entidad de la vida real a la que representa, tiene un estado (es decir, unos atributos con unos valores concretos) y un comportamiento (es decir, tiene funcionalidades o sabe hacer unas acciones concretas).
Es posible que algunos ya hayáis entendido qué es un objeto, pero seguramente muchos todavía no. Por ello, vamos con la explicación informal, que debería lograr que todos entendieseis qué es un objeto.
Informalmente, podemos decir que un objeto es cualquier elemento único del mundo real con el que se pueda interactuar.

1.2.¿Qué es una clase?

El concepto clase está íntimamente relacionado con el concepto objeto.
Podemos definir informalmente una clase como una plantilla (o esqueleto o plano) a partir de la cual se crean los objetos.
Por ejemplo, en el mundo hay millones de televisores de la misma marca y modelo. Cada uno de esos televisores ha sido montado a partir de un mismo plano/esqueleto/plantilla y, consecuentemente, todos ellos tienen los mismos componentes, conexiones y funcionalidades. Ese plano/esqueleto/plantilla es, en términos de programación orientada a objetos, una clase.
Por consiguiente, una clase describe las características y el comportamiento de un conjunto de objetos similares en un contexto determinado.

1.3.Relación entre la clase y los objetos

En este punto tiene que quedar claro que, cuando hablamos de objeto, hacemos referencia a una estructura que hay en un momento determinado de la ejecución del programa, mientras que cuando hablamos de clase hacemos referencia a una estructura que representa a un conjunto de objetos. Esto implica que:
El tipo de un objeto, en vez de ser de un tipo básico (por ejemplo, int, char, float, etc.), es una clase concreta definida por el programador.
Así pues, si tenemos la clase Persona, en ella están representadas las propiedades que caracterizan a una persona (entidad del mundo real), mientras que los diferentes objetos (por ejemplo, Elena, Marina y David) representan a personas concretas.
Lo mismo ocurre con la clase Televisor y con los objetos miTelevisor, tuTelevisor, elTelevisorDelVecino, etc. Por un lado, la clase Televisor representa el concepto abstracto de televisor (es decir, las características y acciones comunes de los televisores), mientras que los tres objetos declarados –miTelevisor, tuTelevisor y elTelevisorDelVecino– son televisores concretos.
Finalmente, veamos dos ejemplos que deberían servir para acabar de entender qué es un objeto y una clase, así como la relación entre los dos.
Ejemplo 1
Si estamos en una reunión familiar, cada persona de la familia es única y se puede interactuar con ella. Es decir, cada persona de esa reunión es un objeto. Así pues, Marina, su madre Elena y su padre David son, cada uno de ellos, objetos. Es más, si el bisabuelo y el abuelo paternos de Marina se llaman ambos Manuel, cada uno de ellos es un objeto diferente, puesto que si bien se llaman igual, no son la misma persona (es decir, el mismo objeto). El bisabuelo y el abuelo, así como el resto de integrantes de la familia, son elementos con los que se puede interactuar de manera individual. Eso sí, todas los miembros de la familia son del mismo tipo Persona (que es la clase a la que pertenecen).
Ejemplo 2
Cuando vamos a una tienda de electrodomésticos a comprar un televisor, lo más probable es que nos encontremos no con una tele, sino con más de una. Cada uno de esos televisores es un objeto, aunque pertenezcan a la misma marca y al mismo modelo. Pensemos que dos televisores del mismo modelo, aunque aparentemente parezcan idénticos, no tienen por qué ser iguales. Simplemente hay que pensar que uno puede estar encendido –porque está en el aparador– y el otro apagado porque está dentro del embalaje. Es decir, tienen estados diferentes. Es más, aunque ambos estén apagados y, por consiguiente, tengan el mismo estado, ¡puedes tocarlos y ver que son dos objetos diferentes! Eso sí, ambos televisores pertenecen a la clase Televisor.
Así pues, tu perro, tu televisor, tu bolígrafo son objetos diferentes a mi perro, mi televisor y mi bolígrafo, aunque sean de la misma raza, modelo y color, respectivamente. Es más, si tienes dos perros de la misma raza, por muy iguales que sean, cada uno de ellos es único y, por consiguiente, son dos objetos distintos.

2.Clase

En este apartado entraremos en detalle en el concepto clase y veremos cuestiones relacionadas con el paradigma de la programación orientada a objetos.

2.1.Analogía con la programación estructurada

Para entender mejor qué es una clase desde un punto de vista más próximo a la implementación, haremos dos analogías con dos conceptos que ya conocéis de la asignatura anterior de programación: el módulo y la tupla.
2.1.1.Módulo
La primera de las analogías ya la habíamos comentado en el módulo «Introducción al paradigma de la programación orientada a objetos» cuando explicábamos cómo se evolucionó de la programación estructurada a la orientada a objetos. La idea es ver una clase como un módulo de la programación estructurada. De este modo, un objeto es del tipo de un módulo, el cual tiene variables (que en POO llamamos atributos) y funciones (llamados métodos en POO).
De esta manera, podemos imaginar que tenemos un módulo Moto que contiene la variable velocidad y dos funciones que permiten modificar y consultar el valor de la variable velocidad, respectivamente. Así, si tengo el objeto m1 del tipo Moto, puedo acceder a su variable velocidad y a sus funciones de modificación y consulta.
2.1.2.Tupla
Si la explicación anterior no la veis clara, os proponemos otra. ¿Os acordáis de las tuplas? Una tupla (o registro o, en inglés, record) es un tipo de dato estructurado, heterogéneo, de acceso directo y de medida fija. Si recordáis, lo más habitual es crear un tipo propio (es decir, ad hoc para el problema que estamos tratando) del tipo tupla. En pseudocódigo sería:
tipo
   coordenadas = tupla
      x, y: real;
   ftupla
ftipo
var
   punto1, punto2: coordenadas;
fvar
En lenguaje C un tipo tupla se define como:
typedef struct coordenada{
x, y: float;
}coordenada_t;
coordenada_t punto1, punto2;
Gracias a las tuplas podemos tener tipos personalizados más complejos y abstractos que incluyen otros tipos, ya sean básicos, de tipo tabla o incluso de tipo tupla. Las tuplas nos permiten hacer operaciones como:
punto1.x := punto1.x +1;
punto1.y := punto2.y;
...
Pues bien, si las tuplas solo pueden tener variables en su definición, una clase puede tener funciones además de variables. Así pues, inventándonos un pseudocódigo para definir las clases tendríamos:
tipo
   rectangulo = clase
      x, y, alto, ancho: real;
      area: funcion():real
             retorna alto*ancho;
         ffuncion
   fclase
ftipo
var
   rect1, rect2: rectangulo;
fvar
De esta forma tenemos una clase llamada rectángulo que nos permite crear objetos de tipo rectángulo. De hecho, en el ejemplo anterior hemos creado dos objetos, rect1 y rect2. Ahora podríamos hacer operaciones como las siguientes:
rect1.x = 5;
rect1.y = 10;
escribeReal(rect1.area());//devolverá el valor 50, resultado de 5*10

2.2.Miembros de una clase

Como hemos visto, una clase está formada por unas variables y unas funciones. Estrictamente hablando en términos de POO, a las variables se les llama atributos y a las funciones se les llama métodos. A su vez, al binomio formado por los atributos y los métodos se le denomina miembros de una clase. Así pues, tanto un atributo como un método son miembros de la clase.
2.2.1.Atributos
Los atributos, también llamados campos, son variables que codifican el estado de un objeto.
Si tenemos la clase Persona con los atributos nombre y edad –de tipo cadena de caracteres y entero, respectivamente–, cada objeto que se defina del tipo Persona tendrá estos dos atributos.
El estado de cada objeto Persona dependerá de los valores que se les asigne a estos dos atributos, tal como se ve en la figura siguiente.
81514_m2_001.gif
Como podemos ver en la figura, cada objeto Persona tiene estados diferentes, es decir, valores distintos para cada atributo.
Aunque dos objetos compartan el mismo estado –es decir, mismos valores para todos sus atributos–, estos dos objetos son diferentes. Solo hay que pensar que puede haber dos personas llamadas David de edad 32 años en el mundo y, obviamente, son personas (u objetos) diferentes.
2.2.2.Métodos
Los métodos implementan el comportamiento de un objeto o, dicho de otro modo, las funcionalidades que un objeto es capaz de realizar.
Haciendo una analogía con la programación estructurada, los métodos serían como funciones (devuelvan algo o no). De ahí que un método, además de por el nombre, se caracteriza por los argumentos (o también llamados parámetros) de entrada que recibe y por el valor de retorno que resulta de ejecutar el comportamiento que implementa. La descripción de estos elementos se conoce como firma del método o signatura del método. En pseudocódigo sería:
nombreMetodo(param1:tipo,...,paramN:tipo):tipoRetorno
En el caso de la clase Persona, algunos métodos podrían ser:
hablar(texto:tabla[30] de caracteres):void
andar(velocidad:entero):void
El patrón que sigue la firma de los métodos depende de cada lenguaje de programación.
En este punto, cabe mencionar el concepto de sobrecarga.
La sobrecarga se produce cuando dos o más métodos tienen el mismo nombre pero diferente número y/o tipo de argumentos.
Dicho de otro modo, la firma del método se diferencia en la parte de los argumentos. Un ejemplo de sobrecarga del método hablar podría ser:
hablar(texto:tabla[30] de caracteres):void
hablar(texto:tabla[30] de caracteres, velocidad:entero):void
El compilador decide qué método (cuál de los dos hablar) invocar comparando los argumentos de la llamada con los de la firma.

2.3.Constructor y destructor

Las clases tienen dos tipos de métodos especiales llamados constructor y destructor que no se consideran miembros de una clase, como tales. No son miembros de la clase porque ni el constructor ni el destructor se heredan.
La mayoría de los lenguajes de programación orientados a objetos implementan el método constructor, incluso algunos obligan a codificar explícitamente uno. No ocurre lo mismo con el destructor, cuya codificación se puede obviar en muchos lenguajes, por ejemplo, en Java.
2.3.1.Constructor
El constructor se llama de forma automática cuando se crea un objeto para situarlo en memoria e inicializar los atributos declarados en la clase. En la mayoría de lenguajes, el constructor tiene las siguientes características:
1) Normalmente, el nombre del constructor es el mismo que el de la clase.
2) El constructor no tiene tipo de retorno, ni siquiera void.
3) Puede recibir parámetros (o también llamados argumentos) con el fin de inicializar los atributos de la clase para el objeto que se está creando en ese momento.
4) En general suele ser público, pero algunos lenguajes permiten que sea privado.
Hay lenguajes que permiten crear más de un constructor, por ejemplo C++, C# y Java, entre otros. En estos casos, al constructor sin parámetros/argumentos se le suele llamar constructor por defecto o predeterminado, mientras que aquellos que tienen parámetros se les llama constructores con argumentos. Como se puede apreciar, decir «constructor por defecto» y «con argumentos» es lo mismo que decir que se hace una sobrecarga del constructor. Debido a la sobrecarga, la única limitación cuando se quiere (y se puede) crear más de un constructor es que no pueden declararse varios constructores con el mismo número y el mismo tipo de argumentos.
En los lenguajes en los que solo se puede codificar un constructor –por ejemplo, PHP5 y Python–, a este se le llama simplemente constructor.
En muchos lenguajes, como por ejemplo Java o C#, si no se define ningún constructor para la clase, el propio compilador creará un constructor por defecto –es decir, sin argumentos– que no hará nada especial más allá de ubicar el objeto en memoria. En el momento en que el programador implementa un constructor, el compilador no añadirá automáticamente el constructor por defecto, aunque el contructor implementado por el programador sea con argumentos.
Por último, hay que resaltar que, en muchos lenguajes, no es obligatorio que una clase tenga un constructor por defecto. Puede interesarnos que todos sus constructores sean con argumentos.
2.3.2.Destructor
El destructor es el método que sirve para eliminar un objeto concreto definitivamente de memoria. Hay que tener en cuenta que:
1) No todos los lenguajes necesitan implementar un método destructor, este es el caso de Java y C#.
2) Por norma general, una clase tiene un solo destructor.
3) En algunos lenguajes no tiene tipo de retorno, ni siquiera void. En otros, generalmente, tiene void como tipo de retorno.
4) No recibe parámetros.
5) En general suele ser público.
La manera en la que se declara el método destructor varía entre lenguajes. Por ejemplo, en C++ y C#, el nombre del destructor es el mismo que el de la clase precedido por el símbolo ~, por ejemplo ~Persona().
En Java, en cambio, se usa el método especial finalize() que no devuelve nada (en este caso, sí tiene tipo de retorno, concretamente void). El compilador de Java no obliga a implementar el método finalize(). Así pues, solo se debe codificar si realmente es necesario.

2.4.Representación de una clase en UML

Para definir una clase de una manera formal y gráfica, se suele utilizar el diagrama de clases del lenguaje UML (Unified Modeling Language).
Utilizar un lenguaje de modelización como el UML permite leer y entender lo que representa una clase sin que sea necesario ver el código.
Este lenguaje gráfico define una clase como una caja compuesta de tres partes. Veamos un ejemplo en la figura siguiente para la clase Persona.
81514_m2_002.gif
Vemos que hay tres partes bien diferenciadas mediante una raya:
1) La primera de ellas, en la parte superior, indica el nombre de la clase, en este caso, Persona.
2) La parte central define los atributos de la clase –nombre y edad– y el tipo al que pertenecen. Para cada atributo hay que indicar el tipo que debería ser con independencia de si el lenguaje de programación lo soporta o no. Por ejemplo, podríamos decir que un atributo debería ser del tipo Date para indicar que debe ser una fecha. En Java existe el tipo Date (es una clase), pero en PHP no. Así pues, en PHP deberíamos o bien hacer que ese atributo fuera del tipo permitido por PHP que mejor modele las características de una fecha (por ejemplo, un String) o bien hacer varios atributos tipo int, es decir, uno para el día, otro para el mes y otro para el año.
3) La parte de abajo define los métodos de la clase indicando su firma, es decir, los parámetros que recibe y su tipo, así como el tipo de valor que devuelve. En caso de no devolver nada, no se indica ningún tipo de devolución.
También podemos observar que se definen los constructores (en este caso el por defecto y dos con argumentos) así como el destructor (en los lenguajes en que es posible implementar un destructor).
En este punto, cabe destacar que el diagrama de clases UML que hemos representado para la clase Persona no es completo, lo acabaremos de completar en el módulo «Encapsulación y extensión». Este diagrama solo define lo que hemos visto hasta ahora.
Setter’s y getter’s
En las clases se suelen crear métodos para asignar y consultar los valores de sus atributos. Al método que asigna el valor se le llama setter (por eso su nombre es set + el nombre del atributo) y al que consulta se le llama getter (de ahí que su nombre sea get + el nombre del atributo). En el ejemplo anterior, el método setter del atributo nombre es setNombre y el método getter del mismo atributo es getNombre.

2.5.Implementación de una clase

A falta de un pequeño detalle, hemos visto cómo representar una clase utilizando el lenguaje gráfico UML. Incluso hemos visto un pseudocódigo de una clase basándonos en el concepto de tupla.
Ahora vamos a ver cómo se implementa una clase en un lenguaje de programación real. En este caso será Java, pero en otros lenguajes la sintaxis es muy similar. La clase a codificar será la clase Persona representada en el diagrama de clases anterior.
class Persona{
   String nombre;
   int edad;

   //Constructor por defecto
   Persona(){
      nombre = "Fulanito";
      edad = 0;
   }
   //Constructor con 1 argumento
   Persona(String nombreNuevo){
      nombre = nombreNuevo;
   }
   //Constructor con 2 argumentos
   Persona(String nombreNuevo, int edadNueva){
      nombre = nombreNuevo;
      edad = edadNueva;
   }
   //Método getter del atributo "nombre"
   String getNombre(){
      return nombre;
   }
   //Método setter del atributo "nombre"
   void setNombre(String nombreNuevo){
      nombre = nombreNuevo;
   }
   //Método getter del atributo "edad"
   int getEdad(){
      return edad;
   }
   //Método setter del atributo "edad"
   void setEdad(int edadNueva){
      edad = edadNueva;
   }
   void hablar(String texto){
      //TODO: aquí va el código. La etiqueta "TODO" (del inglés "to do") se suele 
      //usar en comentarios para decir que algo está pendiente de hacer
   }
   void andar(int velocidad){
      //TODO: aquí va el código
   }
}
Comentario sobre el código fuente
No aparece el método destructor porque en Java no existe como tal y, en este caso, no es necesario crear el método finalize.
En Java (y en muchos otros lenguajes), el código de una clase va en un único fichero cuyo nombre es el mismo que el de la clase.
Por consiguiente, el código de la clase Persona va en el fichero Persona.java.

3.Objeto

En este apartado entraremos en detalle en el concepto objeto y veremos conceptos nuevos como instancia y mensaje.

3.1.Instancia

Como ya hemos comentado, los objetos son ejemplares de una clase. Así pues, a la hora de crear un objeto, debemos seguir los siguientes pasos:
1) Declarar el objeto.
Persona persona1;
2) Instanciar el objeto (crear un objeto a partir de una clase).
persona1 = new Persona("David");
En la mayoría de lenguajes, para instanciar/crear un objeto nuevo debemos escribir la palabra new seguida de uno de los constructores de la clase. En este caso, hemos usado uno de los dos constructores con argumentos, pero también podríamos haber usado el constructor por defecto.
3) En este momento ya tenemos el objeto persona1 del tipo Persona creado en memoria. Así pues, ya podemos acceder a sus atributos y métodos.
Los pasos 1 y 2 se pueden agrupar en un único paso:
Persona persona1 = new Persona("David");
Debido a que la acción de crear un objeto a partir de una clase se le llama instanciar, muchas veces a los objetos se les llama instancia. Así pues, persona1 es una instancia o un objeto de Persona.

3.2.Estado y comportamiento

Como hemos leído en la definición formal de objeto, todo objeto en la POO tiene un estado y un comportamiento. Esto es así porque los objetos (o entidades) de la vida real comparten estas dos características.
Debemos entender que el estado de un objeto viene definido por los valores que toman en un instante determinado los atributos que definen ese objeto.
Por su parte, el comportamiento del objeto se puede entender como las funcionalidades que ese objeto es capaz de realizar. Estas funcionalidades que definen el comportamiento de un objeto las define la clase a la que pertenece dicho objeto mediante los métodos de la clase.
Veamos varios ejemplos para entender mejor estos dos conceptos y ver cómo cualquier entidad (u objeto) de la vida real tiene un estado y un comportamiento:
  • Un perro tiene un estado (nombre, raza, color, etc.) y un comportamiento (ladrar, enterrar huesos, mover la cola, etc.).

  • Un coche también tiene un estado (velocidad actual, marcha actual, color, longitud, ancho, etc.) y un comportamiento (subir marcha, bajar marcha, encender intermitente, etc.).

  • Un rectángulo tiene un estado (coordenadas de origen x e y, altura y ancho) así como un comportamiento (área, perímetro, modificar el valor de x, modificar el valor de y, modificar el valor de la altura, modificar el valor del ancho, etc.).

  • De igual modo, un televisor tiene un estado (encendido o apagado, canal actual, volumen actual, etc.) y un comportamiento (encender, apagar, cambiar a un canal concreto, incrementar el número de canal, decrementar el número de canal, aumentar el volumen, disminuir el volumen, sintonizar, etc.).

  • Incluso una factura tiene un estado (cobrada o no, importe total, paga y señal abonada, etc.) y un comportamiento (cambiar de no cobrada a cobrada y viceversa, modificar el valor del importe total, etc.).

  • Hasta algo más abstracto/intangible como un contacto del teléfono tiene un estado (nombre, apellido, teléfono, correo electrónico, etc.) y un comportamiento (introducir un atributo –es decir, nombre, apellido, teléfono, correo electrónico, etc.–, modificar el valor de un atributo y consultar el valor de un atributo).

Así pues, si un televisor concreto (el objeto) tiene el atributo canal actual igual a 5, ese televisor está en un estado diferente a si tuviera el canal actual igual al número 6.
Si nos fijamos en los ejemplos anteriores, nos daremos cuenta de que hay dos tipos de métodos:
1) Aquellos que hacen acciones que realiza la entidad real (por ejemplo, ladrar en el caso del perro, calcular el área de un rectángulo, la acción de encenderse de un televisor, etc.).
2) Aquellos que operan directamente sobre los atributos del objeto. Por un lado, están los métodos que modifican el valor de los atributos del objeto (por ejemplo, modificar el número de teléfono de un contacto o el canal actual de un televisor) y que, por consiguiente, cambian el estado del objeto. Por otro lado, están los métodos que consultan el valor de los atributos del objeto (por ejemplo, consultar el número de teléfono de un contacto o el canal actual de un televisor). Estos métodos de modificación y consulta son llamados setter y getter, respectivamente.

3.3.Mensaje

Cuando los objetos quieren interactuar entre ellos utilizan mensajes. Un mensaje es la manera que existe de acceder a los atributos y métodos de un objeto. La forma de un mensaje, en la mayoría de lenguajes, sigue la siguiente sintaxis:
variable_del_objeto.miembro
donde miembro es un atributo o un método de la clase. Así pues, para el ejemplo de la clase Persona, tenemos que:
//Instanciamos dos objetos del tipo "Persona" con dos constructores con argumentos diferentes
Persona persona1 = new Persona("David",32);
Persona persona2 = new Persona("Marina");

//Accedemos al atributo "nombre" para asignarle un nuevo valor, cambiamos "David" 
//por "Elena".
persona1.nombre = "Elena";

//Accedemos al atributo "nombre" del objeto "persona1" para consultar su valor. 
//El valor "Elena" se guardará también en la variable "nombreAux".
String nombreAux = persona1.nombre;

//Accedemos a un método de lectura/consultivo que nos devolverá "Elena", 
//al ser éste el valor del atributo "nombre" del objeto "persona1";
nombreAux = persona1.getNombre();

//Accedemos al método de escritura que asignará el valor 1 al atributo 
//"edad" del objeto "persona2".
persona2.setEdad(1);

//Podemos saber la edad del objeto "persona2" de dos formas, accediendo 
//al atributo "edad" directamente o mediante la función getter correspondiente.
int edadAux = persona2.edad;
edadAux = persona2.getEdad();
El ejemplo anterior es correcto, pero no es la práctica más habitual. ¿Por qué? Como ya comentamos en el módulo «Introducción al paradigma de la programación orientada a objetos», una de las razones que motivaron un cambio respecto al paradigma de la programación estructurada fue ocultar los datos (es decir, los atributos) y obligar a los programadores a usar funciones para consultar y modificar sus valores (es decir, usar los métodos getter y setter). En otras palabras, se veía necesario crear algún mecanismo para controlar el acceso a los datos. Es decir, no deberíamos acceder –ya sea para consultar o modificar– a los atributos de la siguiente manera:
persona1.nombre = "Elena";
int edadAux = persona2.edad;
persona1.setNombre("Elena");
int edadAux = persona2.getEdad();
Sino que deberíamos acceder del siguiente modo:
persona1.setNombre("Elena");
int edadAux = persona2.getEdad();
Así pues, la programación orientada a objetos dio respuesta a esta necesidad de ocultar la información mediante lo que se conoce como encapsulación.

3.4.Viendo el mundo de otra forma

Es hora de hacer un descanso y detenernos un momento para reflexionar.
Da igual dónde estés, aparta la mirada de esta página y mira a tu alrededor, ¡pero vuelve, que tienes que seguir leyendo! ¿Qué ves? Quizás respondas: cosas. Bueno, no está mal, pero intentemos usar una palabra más rica. Digamos: entidades. No está mal, pero ¿qué tal si buscamos una palabra que no sea ni tan vulgar ni tan culta y que, además, haya aparecido en estos apuntes? ¿Qué tal si decimos que lo que ves a tu alrededor son objetos?
A partir de este momento, ya no mirarás el mundo que te rodea de igual manera. Ahora deberías estar viendo objetos –incluidos los seres vivos– que interactúan entre ellos.
Pongamos que estás en el despacho donde estudias o, mejor, en el sofá del comedor (el estudio no es incompatible con la comodidad). Seguramente verás objetos muy diferentes, unos más simples y otros más complejos. Por ejemplo, la lámpara que tienes al lado seguramente solo tiene dos estados (encendido y apagado) y dos comportamientos (encender y apagar). Otros, en cambio, como el televisor, tienen más estados y comportamientos.
Es más, un objeto puede ser tan complejo que puede incluso estar formado/compuesto por otros objetos. Sin ir más lejos, un televisor tiene un mando a distancia, que es otro objeto. O, si no lo ves claro, un coche tiene un volante, cuatro ruedas, etc. y cada uno de ellos es un objeto (cada rueda es un objeto independiente). O, para verlo aún más claro, un teléfono inteligente es un objeto que dentro tiene una lista de apps, donde cada app es un objeto.
Quizás en este momento has levantado la mirada y te has dado cuenta de que, en tu despacho, hay una lámpara en el techo además de la lámpara fluorescente que hay encima de tu mesa. ¡Ostras, dos objetos «lámpara»! Hum Mmmm..., tienen características y comportamientos similares. ¡Ambos objetos son del tipo Lámpara! O mejor, ¡ambos objetos son de la clase Lámpara!
Tras leer sobre el paradigma de programación orientada a objetos (POO), tu forma de mirar el mundo debería haber cambiado. Si no lo ha hecho todavía, tranquilo/a, que cuando empieces a programar siguiendo la POO, este clic mental lo harás irremediablemente.

Resumen

En este módulo hemos prestado especial atención, como no podía ser de otra manera, a los conceptos de objeto y clase, así como a la relación que hay entre ellos.
Además, hemos tenido un primer contacto con el lenguaje de modelado de sistemas de software, UML (Unified Modeling Language). Concretamente, hemos visto cómo se representa una clase en un diagrama de clases realizado con este lenguaje.
Inevitablemente, hemos visto código propio de los lenguajes orientados a objetos, siendo Java el lenguaje utilizado en los ejemplos.

Bibliografía

Booch, G.; Jacobson, I.; Rumbaugh, J. (1999). El lenguaje de modelado unificado UML. Madrid: Addison-Wesley Iberoamericana.
Joyanes, L. (1998). Programación orientada a objetos. Madrid: McGraw-Hill.
Meyer, B. (1997). Object-oriented software construction. Santa Bárbara: Prentice Hall.
Rumbaugh, J.; Blaha, M.; Premernali, W.; Eddy, F.; Lorensen, W. (1996). Modelado y diseño orientado a objetos. Madrid: Prentice Hall.
Sommerville, I. (2005). Ingeniería del software. Madrid: Pearson-Addison Wesley.