Encapsulación y extensión de tipos

POO es una manera equilibrada de enfocar la escritura del software. Los datos y el comportamiento están empaquetados juntos. Esta encapsulación crea tipos de datos definidos por el usuario, que amplían los tipos de datos del lenguaje y se interactuan. La extensión de tipos es una posibilidad de agregar al lenguaje los tipos de datos definidos por el usuario, los cuales también pueden ser usados de una manera fácil, igual que los tipos básicos.

Un tipo de dato abstracto, por ejemplo una cadena, es una descripción del comportamiento ideal, muy bien conocido. El usuario de la cadena sabe que las operaciones, tales como la concatenación o la impresión, tienen un cierto comportamiento. Las operaciones de concatenación e impresión se llaman métodos.

La implementación concreta de TDA puede tener ciertas restricciones; por ejemplo, las cadenas pueden ser limitadas en su longitud. Estas limitaciones afectan el comportamiento abierto para todos. Al mismo tiempo, los detalles internos o privados de implementación no afectan directamente el modo como el usuario ve el objeto. Por ejemplo, una cadena a menudo se implementa como un array; mientras que la dirección básica interna de los elementos de este array y su nombre no son tan significativos para el usuario.

La encapsulación es la capacidad de ocultar los detalles internos cuando se proporciona un interfaz abierto al tipo definido por el usuario. En MQL5, igual que en C++, para la provisión de encapsulación se utilizan las definiciones de clase y estructura (class y struct) en combinación con las palabras claves de acceso private (privado), protected (protegido) y public (público).

La palabra clave public indica que el acceso a los elementos que la siguen está abierto sin ningunas restricciones. Sin esta palabra clave los elementos de la clase están cerrados por defecto. Los elementos cerrados están disponibles sólo para las funciones miembro de su clase.

Los elementos de clase protegidos están disponibles para las funciones miembro no sólo de su clase, sino también de las clases heredadas. Los elementos de acceso abiertos están disponibles para cualquier función dentro de la zona de visibilidad de declaración de la clase. La protección permite ocultar una parte de implementación de clase, evitando de esa manera los cambios imprevistos de la estructura de datos. La restricción de acceso o ocultación de datos son particularidades de la programación orientada a objetos.

Habitualmente procuran proteger los elementos de clase y declararlos con el modificador protected. El establecimiento y la lectura de valores de estos elementos se realiza usando los métodos llamados método-set y método-get, los cuales se definen con el modificador de acceso public.

Ejemplo:

class CPerson
  {
protected:
   string            m_name;                     // nombre
public:
   void              SetName(string n){m_name=n;}// establece el nombre
   string            GetName(){return (m_name);} // devuelve el nombre
  };

Este enfoque ofrece varias ventajas. Primero, por el nombre de la función se puede entender qué es lo que hace: establece o recibe el valor de un elemento de clase. Segundo, tal vez en el futuro tengamos necesidad de cambiar el tipo de variable m_name en la misma clase CPerson o en alguna de sus clases derivadas.

En este caso, bastará con cambiar la implementación de la función SetName() y GetName(), mientras que los objetos de la clase CPerson se podrá usar en el programa sin ningunas modificaciones en el código, porque el usuario ni siquiera va a enterarse de que el tipo de datos  m_name se haya cambiado.

Ejemplo:

struct Name
  {
   string            first_name;                 // nombre
   string            last_name;                  // apellido
  };
 
class CPerson
  {
protected:
   Name              m_name;                     // nombre
public:
   void              SetName(string n);
   string            GetName(){return(m_name.first_name+" "+m_name.last_name);}
private:
   string            GetFirstName(string full_name);
   string            GetLastName(string full_name);
  };
 
void CPerson::SetName(string n)
  {
   m_name.first_name=GetFirstName(n);
   m_name.last_name=GetLastName(n);
  }
 
string CPerson::GetFirstName(string full_name)
  {
   int pos=StringFind(full_name," ");
   if(pos>0) StringSetCharacter(full_name,pos,0);
   return(full_name);
  }
 
string CPerson::GetLastName(string full_name)
  {
   string ret_string;
   int pos=StringFind(full_name," ");
   if(pos>0) ret_string=StringSubstr(full_name,pos+1);
   else      ret_string=full_name;
   return(ret_string);
  }

Véase también

Tipos de datos