domingo, 20 de marzo de 2016

Encapsulamiento de los atributos de una clase

Antes de nada, debe quedar claro que el encapsulamiento, igual que cualquier buen hábito de programación (como no poner goto, comentar, etc) es útil para código que más adelante se puede querer reutilizar o modificar, por otras personas o por uno mismo. Si yo hago un programa de marcianos y nunca jamas pienso volver a tocarlo, da igual que lo haga con gotos y sin comentar mientras me entere yo mismo mientras lo estoy haciendo y funcione. Pagaré este "pecado" si dentro de dos meses se me ocurre mejorarlo o quiero reaprovechar algo de su código para otro programa.
Comento esto porque el encapsulamiento, llevado a su extremo, como es el caso del punto final de interfaces, hace la programación un poco más complicada (hay que hacer más clases). Este esfuerzo sólo se ve recompensado si el código es muy grande (evitando recompilados innecesarios) o se va a reutilizar en un futuro (podremos extraer clases con menos dependencias de otras clases). Dicho esto, vamos al tema.
Cualquier curso de orientación a objetos nos dice que es mejor poner los atributos de una clase protegidos o privados (nunca públicos) y acceder a ellos a través de métodos públicos que pongamos en la clase. Veamos el motivo. Supongamos, por ejemplo, que nos piden un programa que permita llevar una lista de gente con sus fechas de nacimiento. Entre otras cosas, decidimos hacernos nuestra clase Fecha con varios métodos maravillosos de la siguiente manera.
class Fecha
{
   public:
      int anho; // El anho con cuatro cifras, ej. 2004
      int mes;  // El mes, de 1 a 12
      int dia;    // El dia, de 1 a 31
      void metodoMaravilloso1();
      void metodoMaravilloso2();
};
Ya hemos hecho la clase. Ahora hacemos el resto del código y en unos varios miles de líneas de código usamos directamente cosas como esta.
Fecha unaFecha;
unaFecha.anho = 2004;
unaFecha.mes = 1;
unaFecha.dia = 25;
Finalmente acabamos nuestro programa y todo funciona de maravilla. Unos días después nos dicen que el programa va a guardar tropecientas mil personas y que ocupan mucho los ficheros, que a ver si podemos hacer algo para remediarlo. ¡Vaya!, almacenamos una fecha con tres enteros. Si usamos el formato de la mayoría de los ordenadores, en el que la fecha es el número de segundos transcurridos desde el 1 de Enero de 1970 (lo que nos devuelve la función time()), basta con un entero.
Total, que manos a la obra, cambiamos nuestra clase para que tenga lo siguiente:
class Fecha
{
   public:
      /* Comentado por ineficiente
      int anho; 
      int mes; 
      int dia;   */
      long numeroSegundos;
      void metodoMaravilloso1();
      void metodoMaravilloso2();
};
Ya está hecho lo fácil. Ahora sólo hay que ir por las tropecientas mil líneas de código cambiando nuestras asignaciones y lecturas a los tres enteros anteriores por el nuevolong.
Hubiera sido mucho mejor si hubieramos hecho estos tres enteros protegidos y unos métodos para acceder a ellos. Algo como esto
class Fecha
{
   public:
      void tomaFecha (int anho, int mes, int dia);
      int dameAnho ();
      int dameMes ();
      int dameDia ();
      void metodoMaravilloso1();
      void metodoMaravilloso2();
   protected:
      int anho; // El anho con cuatro cifras, ej. 2004
      int mes;  // El mes, de 1 a 12
      int dia;    // El dia, de 1 a 31
};
Si ahora tenemos que hacer el mismo cambio, basta con cambiar los atributos protegidos. Los métodos tomaXXX() y dameXXX() se mantienen en cuanto a parámetros y valor devuelto, pero se modifica su código interno para que conviertan el año,mes y dia en un long de segundos y al revés. El resto del código no hay que tocarlo en absoluto.
Es incluso mejor hacer los atributos privados que protegidos. Haciéndolos protegidos, las clases hijas (las que heredan de Fecha) pueden acceder directamente a estos atributos. Cuando hagamos el cambio por un long, debemos cambiar también el código de las clases hijas. Si los atributos son privados y obligamos a las clases hijas a acceder a ellos a través de métodos, tampoco tendremos que cambiar el código de estas clases hijas.
El acceso a través de métodos es menos eficiente que hacerlo directamente, así que aunque siguiendo el principio de ocultación es mejor hacer atributos privados, por eficiencia en algunos casos quizás sea mejor hacerlos protegidos (o incluso públicos) a riesgo de tener que cambiar más líneas de código en caso de cambio.

No hay comentarios:

Publicar un comentario