lunes, 12 de junio de 2017

Capítulo 88: Separar la interfaz de la implementación en C++


Diario de un programador. Día 190
Separar la interfaz de la implementación

La interfaz de una clase:

Una interfaz nos permite poder interactuar con un sistema, cualquiera que sea. Por ejemplo, un televisor puede poseer botones, los cuales funcionan como una interfaz entre nosotros y los componentes internos del televisor.  El televisor podría tener un botón para ajustar el volumen, otro para cambiar de canal, otro para encender el televisor, etc.
Otro ejemplo de interfaz podría ser un horno microondas, el cual posee botones o perillas para ajustar el tiempo, la temperatura, etc. Otro ejemplo de interfaz sería una lavadora, con botones para ajustar el tipo de lavado, cantidad de agua, tipo de ropa etc.
Así como estos ejemplos hay muchos, lo importante es saber que una interfaz nos permite saber o especificar qué operaciones podemos hacer (cambiar de canal, ajustar temperatura, encender, apagar, etc.), pero no cómo funcionan estas operaciones, en otras palabras, una interfaz no indica o muestra cómo es que el control de volumen realiza internamente esa operación. Una interfaz es como un menú de opciones, el usuario escoge una opción y el programa realiza lo que hemos seleccionado. En informática, una interfaz se compone de menús desplegables, botones, íconos, barras de desplazamiento, ventanas, opciones, etc.
La interfaz de una clase se compone por funciones miembro public de la clase.
Con lo anterior dicho, puede surgir la pregunta ¿cómo separar la interfaz de la implementación?
Hasta ahora, la definición de cada clase que hemos hecho contiene las definiciones completas de las funciones miembro public de la clase y las declaraciones de sus miembros de datos private. A pesar de que los programas funcionan de esa manera, una mejor ingeniería de software es definir las funciones miembro fuera de la definición de la clase, para así poder ocultar su implementación. Aprender a trabajar de este modo es útil cuando se trabaja en un grupo de personas, así nos aseguramos que los programadores no escriban código que dependa de los detalles de implementación de la clase, de lo contrario, se corre el riesgo de que el código cliente falle si cambia la implementación de la clase.
Para lograr lo anterior, lo que debemos hacer es dividir nuestro programa en distintos archivos. Vamos a crear un archivo de encabezado .h donde  definiremos una clase (esta será nuestra interface), y dos archivos .cpp, uno de código fuente, en el que definiremos las funciones miembro y  el otro archivo .cpp define el código cliente (la función main).
Antes que nada, para que estos tres archivos se puedan enlazar, (y no muestre un error al momento de compilar) en code blocks debemos crear un proyecto.
Para crear un proyecto, debemos hacer lo siguiente:
Desde el menú File, escoger New y luego seleccionar Project...


Luego, seleccionar Empty project y posteriormente presionar el botón Go.


En la siguiente ventana, presionamos Next.


Ahora se debe seleccionar un título para el proyecto y seleccionar la carpeta donde se guardará nuestro proyecto. Luego presionar Next.


Luego debemos seleccionar el compilador, dejamos GNU GCC Compiler que viene por defecto. Luego nos pide seleccionar al menos UNA configuración. (por defecto vienen seleccionadas las dos) Estas configuraciones son Debug y Release. Principalmente la opción Debug es para obtener un proyecto que se pueda depurar y Release, es básicamente el proyecto ya listo para salir "al mercado", es decir, un proyecto ya depurado y revisado. Como esto es algo que veremos más adelante, simplemente lo dejaremos tal como está y seleccionaremos el botón Finish.


Ahora vamos a crear nuestro primer archivo, el cual será el archivo de cabecera .h, para ello seleccionamos el ícono de New File y seleccionamos Empty file.


Nos va a preguntar si queremos añadir este nuevo archivo al proyecto. Nosotros seleccionamos que sí.


Ahora nos pide que guardemos nuestro archivo. Para este ejemplo, nuestro primer archivo se llamará interface.h
Ahora nos preguntará a cual configuración pertenecerá el archivo, por defecto estarán seleccionadas ambas opciones. Dejaremos esto así por ahora y seleccionaremos el botón Ok.


Ahora sí, ya estamos listos para crear nuestro primer archivo, que como dijimos antes será el archivo de cabecera .h. Este archivo será nuestra interface y por ser un ejemplo, empezare mostrando un programa muy básico. Este solamente mostrará un mensaje por pantalla, pero será suficiente para ver cómo funciona esto.
El código es el siguiente:
//interface.h
#include<iostream>
#include <string>
using std::string;

class ClaseMensaje{

  public:

     ClaseMensaje(string);
     void setPalabra(string);
     string getPalabra();

  private:

    string mensaje;
};

La interface que se presenta, tiene una clase llamada ClaseMensaje. Dentro de esta clase lo que hacemos es definir los prototipos. Estos prototipos son los que conforman la interfaz, bastante sencilla pero es una interfaz.
El primer prototipo, ClaseMensaje(string) corresponde al constructor de la clase, el cual recibe un parámetro de tipo string. El segundo prototipo, void setPalabra(string), corresponde a la función que se encargará de establecer la palabra o mensaje que seleccionaremos más adelante. Este prototipo indica que la función recibe un parámetro de tipo string. El tercer prototipo, void getPalabra(string), corresponde a la función que se encargará de recuperar la palabra o mensaje que fue anteriormente seleccionada. Posteriormente tenemos una variable de tipo string, llamada mensaje, la cual será ocupada para almacenar el mensaje seleccionado.
Ahora que ya está lista la interface, pasaremos a crear las funciones en otro archivo. El archivo que se creará lo llamaremos funciones.cpp. El código es el siguiente:

//funciones.cpp

#include "interface.h"
  using std::string;

  ClaseMensaje::ClaseMensaje(string palabra){
    setPalabra(palabra);
  }

  void ClaseMensaje::setPalabra(string palabra){
    mensaje = palabra;
  }

  string ClaseMensaje::getPalabra(){
    return mensaje;
  }


En este código se implementan las funciones que vamos a utilizar. Al principio de este código, se debe incluir la directiva del preprocesador #include "interface.h". Más abajo, tenemos el constructor de la clase, el cual utiliza el signo ::, este signo se conoce con el nombre de operador binario de resolución de ámbito. Este sirve para enlazar la interfaz. De no usarlo, entonces el programa produciría un error ya que el compilador no reconocería las funciones. La forma que se muestra para utilizarlo es escribiendo el nombre de la clase que se va a enlazar (que en este caso es la clase ClaseMensaje)seguido de los operador :: y posteriormente el nombre de la función. A parte de esta nueva implementación, las funciones están formadas normalmente. Si se presta atención, se puede ver que las funciones set y get no presentan mayores cambios.
Ya por último vamos a crear la función main. Esta función, como se puede apreciar más abajo, no contiene nada nuevo. Aquí simplemente creamos un objeto de la clase ClaseMensaje, el cual le pasamos como parámetro la palabra "Buenas noches"

//inicio.cpp
#include <iostream>
 #include "interface.h"
 using std::cout;

  int main()
  {
    ClaseMensaje saludo("Buenas noches");

    cout << saludo.getPalabra();

  return 0;
  }

Al compilar y ejecutar el programa, se puede apreciar el resultado


Otro ejemplo similar, pero esta vez solicitando datos sería el siguiente:

Al igual que el anterior ejemplo, aquí empezamos escribiendo la interfaz. Esta quedaría de la siguiente manera:




El código que contiene las funciones quedaría de la siguiente manera:




Y por último, el código main, quedaría de la siguiente manera:


Entonces, al compilar y ejecutar el programa, se obtendría el siguiente resultado:


Bueno, esto es todo por ahora.
Saludos.



Gustavo J. Cerda Nilo
Noviembre 2016
http://codigogx.blogspot.cl/2016/11/capitulo-84-programa-en-archivos.htmlhttps://codigogx.blogspot.cl/2017/11/capitulo-89-c-punteros.html






C++ El apuntador This

El apuntador This En C++, cada objeto tiene acceso a su propia dirección a través de un puntero o apuntador denominado This. Lo...