Mostrando las entradas con la etiqueta Paradigma. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Paradigma. Mostrar todas las entradas

4 de julio de 2017

POO (Consideraciones adicionales).

Respecto al envío de mensajes.
   La sintaxis general en Java para el envío de mensajes a un objeto es la siguiente:

objeto.mensaje(lista_de_argumentos);

donde objeto es un objeto de una clase previamente definida, y mensaje es uno de los métodos públicos definidos para dicha clase. La lista_de_argumentos es una lista de argumentos separada por comas, en donde cada argumento puede ser un objeto, o un tipo de dato primitivo.

Respecto a la sobrecarga de operadores.
   Algunos lenguajes de programación soportan un concepto relacionado con sobrecarga de operadores. La idea general del concepto de sobrecarga se ha planteado en la entrada POO (mensajes y métodos). El lenguaje de programación Java no soporta la sobrecarga de operadores, y por consiguiente, se ha omitido su descripción; sin embargo, es importante que el lector conozca que el concepto de sobrecarga no es exclusivo de los métodos o constructores, ni mucho menos de un lenguaje de programación en particular.
 
    La sobrecarga de operadores en C++ sí existe. En la sección correspondiente a las consideraciones adicionales para las colas de espera, se proporcionan un par de ejemplos al respecto. Para comprenderlos se requiere tener claros los aspectos relacionados con la implementación de la herencia, el funcionamiento de las colas de espera, y su respectiva especialización en la forma de colas de prioridad.

Respecto al paradigma.
   El establecimiento de niveles de acceso como private para los atributos de una clase, así como el uso de métodos de tipo set y get están directamente relacionados con el principio de ocultación de información (information hiding).

   Ahora bien, es probable que el lector haya notado que en la descripción del Ejemplo PruebaHerencia, en distintas ocasiones se hizo referencia a los objetos personacientífico como si fueran en sí mismos personas o entidades existentes. Lo anterior se hizo de manera deliberada, ya que como se comentó en la entrada referente al paradigma orientado a objetos, ésto eleva el nivel de abstracción y permite que se haga referencia a las entidades fundamentales del paradigma (los objetos), como elementos comunes de nuestro lenguaje natural, lo cual permite que los problemas se puedan expresar, al menos en principio, de una manera más natural e intuitiva.

   En este sentido, al dotar a los objetos de una personalidad propia con características y responsabilidades, en lugar de pensar en términos de datos, variables, y funciones o procedimientos que operen sobre dichos datos, se eleva el nivel de abstracción, facilitando con ello el análisis y la comprensión, ya que el problema y su solución pueden ser expresados y analizados en términos de su propio dominio, y no en el del medio (lenguaje de programación) de la solución. Ésta es una de las formas en la que las personas abstraemos, procesamos y utilizamos la información.

   Es sumamente importante que el lector tenga presente que en el paradigma orientado a objetos no se piensa en términos de datos, sino en términos de entidades con características y responsabilidades específicas, por lo que, cuando defina una clase, puede resultar útil el plantearse al menos un par de preguntas que le permitan determinar si los objetos derivados de su clase tienen o no sentido. Adicionalmente, las preguntas pueden ayudar también a establecer o coadyuvar en la meta de mantener una alta cohesión como parte del proceso de diseño e implementación:
  1. ¿Los atributos representan características o propiedades, o definen un estado para los objetos que serán instanciados?
  2. ¿La clase representa en sus métodos servicios, comportamiento, acciones o responsabilidades inherentes a los objetos que deriven de ella?
   Cabe mencionar que las preguntas propuestas son sólo una guía y una sugerencia al lector, no pretenden ser de ninguna manera una lista completa y absoluta. Con estas dos sencillas preguntas, además de validar y verificar su diseño de clases, estará reforzando también el concepto de encapsulamiento.

Respecto al polimorfismo.
   El polimorfismo es la cualidad de objetos heterogéneos de responder de distinta manera a un mismo mensaje. El tipo de polimorfismo más común se da en la herencia, pero no es el único.

   El Ejemplo Heterogéneo es un conjunto de clases (Automóvil, Motocicleta, Perro, Planta, Plomero, Profesor) heterogéneas que contienen un método de servicios. La idea es que, al menos en principio, cada una de dichas entidades ofrecen servicios distintos en función de su constitución y comportamiento general.

   Por otro lado, el Ejemplo Composición contiene tres clases: Libro, Publicación y Revista, las cuales presentan un comportamiento de polimorfismo en la forma en que se auto describen (imprimen), a través del método toString( ).

   En directa relación con el párrafo anterior, el tipo de polimorfismo más común se presenta en el Ejemplo Herencia, el cual contiene también las tres clases Libro, Publicación y Revista pero con un enfoque de polimorfismo basado en la herencia para la forma en que se auto describen (imprimen) a través del método toString( ).

   Existe un concepto en programación denominado latebinding, dynamic bindig o dynamic linkage, el cual se refiere a un mecanismo de programación en el cual el método que responderá al mensaje (el método que será invocado) es determinado en tiempo de ejecución. Como un ejemplo muy simple de esto, tómese el tiempo de comparar y analizar el Ejemplo PruebaHerencia (descrito en la entrada POO (Herencia)) y el Ejemplo PruebaPolimorfismo, en donde se muestra dicho concepto de programación, así mismo, es importante comprender tanto las diferencias de dichos ejemplos como los comentarios que aparecen en el código del Ejemplo PruebaPolimorfismo.

   Considere ahora el siguiente Ejemplo de late binding y tómese el tiempo que considere necesario para comprenderlo con base en el concepto de polimorfismo y  la comprensión de todos y cada uno de los ejemplos anteriores.
 
    Finalmente, una vez que se tengan madurados y comprendidos los ejemplos enunciados y su relación con el polimorfismo, se recomienda revisar también el tema de clases abstractas e interfaces (Java) para complementar dicho concepto.




5 de abril de 2017

Algunas aplicaciones (pilas).

    A continuación se presentan algunas de las aplicaciones más representativas de una pila, cabe mencionar que esta selección es necesariamente incompleta.

Análisis básico de expresiones.
   Considere la siguiente expresión:


   Se insta al lector a que sea tan amable de contestar una por una, las siguientes preguntas:
  • ¿Es clara?, es decir, ¿se entiende?
  • Para valores concretos de x, y, y j, ¿podría evaluarla?
  • ¿Puede escribir la misma expresión en una sola línea de texto, como lo haría para un programa?
   La representación "lineal" de la expresión anterior se muestra a continuación:

7 – ( (x * ( (x + y) / (j - 3) ) + y) / (4 – 5/2) )

   Observe que la expresión anterior contiene paréntesis, los cuales son indispensables para agrupar de manera apropiada las operaciones involucradas, mientras que la primera representación no los tiene, ya que son innecesarios. Ahora bien, en base a lo anterior considere lo siguiente:
  • ¿Cómo saber que la expresión lineal está correctamente balanceada en cuanto a paréntesis se refiere, de tal forma que represente exactamente lo mismo que la expresión original?
  • ¿Y si la expresión original fuera más grande y/o más compleja?
   Considere ahora esta otra expresión:


   Cuya representación “lineal” está dada por:

{x + (y – [a + b]) * c – [ (d + e) ] } / (h – (j – (k – [l - n] ) ) )

   Al igual que antes:
  • ¿Cómo saber si la expresión lineal está correctamente balanceada en cuanto a símbolos de agrupación se refiere? Note que ahora se han introducido otros símbolos de agrupación de expresiones (corchetes y llaves) además de los paréntesis.
  • Adicionalmente, ¿cómo saber que un símbolo de agrupación está cerrando a su correspondiente símbolo de apertura?, es decir, ¿cómo saber que los símbolos de agrupación están correctamente asociados?
   Debería resultar claro que es mucho más fácil para las personas comprender expresiones denotadas como en las expresiones originales; sin embargo, las representaciones "lineales" son las que se utilizan en los lenguajes de programación, por lo que se requiere de un mecanismo que verifique de manera automática que una expresión esté bien escrita, al menos en cuanto a símbolos de agrupación se refiere; para ello, considere el siguiente Algoritmo de verificación de balanceo:

   valida = true;
   p = pila vacía;

   while( no sea fin de cadena y la expresion sea válida ){
      procesar el siguiente símbolo de la cadena;

      if ( símbolo == ‘(’ | | símbolo == ‘[’ | | símbolo == ‘{’ )
         p.push(símbolo);
      else if ( símbolo == ‘)’ | | símbolo == ‘]’ | | símbolo == ‘}’ ){
         if ( p.estaVacia( ) )
            valida = false;
         else{
            char s = p.pop( );
            if ( s no es equivalente a símbolo )
               valida = false;
         }
      }
   }  // while

   if ( !p.estaVacia( ) )
      valida = false;
 
   if ( valida )
      println("La expresión es correcta y está balanceada.”);
   else
      println("Existe error en los símbolos de agrupación.”);

Algoritmo de verificación de balanceo.

   Dada una expresión almacenada en una cadena, el Algoritmo de verificación de balanceo utiliza una pila para realizar la verificación de los símbolos de agrupación que se encuentren en dicha expresión.

   Se deja como ejercicio para el lector realizar una implementación de dicho algoritmo, así como la resolución de los aspectos inherentes a la equivalencia de símbolos (vea el Ejercicio 9 de la entrada Ejercicios selectos para pilas Java y C++ respectivamente).

   Notación interfija, postfija y prefija.
   Considere la suma de dos números cualesquiera A y B. Aplicar el operador “+” a los operandos A y B y representar la suma como A + B tiene el nombre de representación o notación interfija.

   La notación interfija, aunque es la más común, no es la única. Existen al menos otras dos notaciones alternativas para expresar la suma de A y B utilizando los mismos símbolos A, B y +:
  1. + A B representación o notación prefija.
  2. A B + representación o notación postfija.
   Los prefijos “pre”, “pos” e “inter” hacen referencia a la posición relativa del operador en relación a los operandos.

   El llamado o invocación a una función en un lenguaje de programación gobernado por el paradigma estructurado, como el lenguaje C por ejemplo, utiliza notación prefija (considere por ejemplo la suma de dos números enviados a una función invocada mediante suma(a, b)), ya que el operador (suma) precede a los operandos (a, b).

   Conversión de interfija a postfija.
   Considere la siguiente expresión:

A + B x C

la cual implícitamente indica:

A + (B x C)

   Suponga que se desea convertir la expresión anterior a su representación en postfija ¿Cómo proceder?

   Los ejemplos siguientes asumen una representación "lineal" de las expresiones. En base a lo anterior, es importante que el lector tenga presente que el proceso de conversión se basa en las reglas de precedencia de los operadores involucrados en la expresión a convertir.

   Así, para convertir una expresión de su notación interfija a su notación postfija, se tienen lo siguientes pasos:
  1. A + (B x C)     forma interfija.
  2. A + (BC x)    se convierte la multiplicación y el nuevo elemento se considera como un solo número (de hecho, después de aplicar el operador el resultado (producto) es en efecto, otro número).
  3. A (BC x) +    se convierte la suma con las mismas consideraciones expuestas en el punto anterior.
  4. A B C x +     se eliminan paréntesis para obtener la representación final en postfija.
   Con base en lo anterior, es posible afirmar que las dos reglas que se siguen durante el proceso de conversión a postfija son las siguientes:
  1. Las operaciones con mayor precedencia se convierten primero. Si existe más de una operación con la misma precedencia, se resolverá primero la que esté más a la izquierda.
  2. Después de que una parte de la expresión se ha convertido a notación postfija, ésta se considerará como un operando único.
   Ejemplo:
   Dada la siguiente expresión (note que no es la misma que la expresión anterior):

(A + B) x C

convierta dicha expresión a su notación postfija.

   En base a lo expuesto con anterioridad, el proceso de solución está dado por los siguientes pasos:
  1. (A + B) x C    forma interfija.
  2. (A B +) x C    se convierte la adición.
  3. (A B +) C x    se convierte la multiplicación.
  4. A B + C x       se eliminan paréntesis: representación postfija.
   Conversión de interfija a prefija.
   Las reglas para convertir una expresión de su notación interfija a su notación prefija son idénticas a las de conversión de interfija a postfija. El único cambio a considerar es que ahora el operador se coloca antes de los operandos en lugar de colocarlo después de ellos.
 
   Aspectos a considerar.
Finalmente, respecto a las notaciones prefija y postfija cabe hacer mención de un par de consideraciones:
  1. La representación prefija no siempre es una imagen reflejo de la representación postfija.
  2. El orden de los operadores en las expresiones postfijas determina el orden real de las operaciones al evaluar la expresión, haciendo en consecuencia innecesario el uso de paréntesis.
   En la entrada correspondiente a los Ejercicios selectos para pilas Java y C++ respectivamente tendrá la oportunidad de practicar y de ampliar su experiencia al respecto.

   Evaluación de expresiones.
   Aunque para las personas en general es más fácil y natural comprender las expresiones interfijas (quizá porque en su mayoría así fuimos instruidos y así estamos acostumbrados pero, ¿qué pasaría si desde pequeños, en lugar de haber aprendido a realizar operaciones utilizando notación interfija, se nos hubiera enseñado a realizarlas utilizando notación prefija por ejemplo? ¿Qué sería entonces lo fácil y natural de comprender?), el procesamiento de dichas expresiones por medio de una computadora no es nada sencillo.

   Considere lo siguiente: dada una expresión en notación interfija con valores específicos ¿Cómo evaluaría algorítmicamente dicha expresión? Piense y reflexione en ello antes de continuar.

   Ahora bien, con valores específicos para una expresión en notación postfija ¿Cómo evaluaría algorítmicamente dicha expresión? Para esto último, considere el siguiente Algoritmo de evaluación de una expresión en notación postfija:

         pilaOperandos = pila vacía;

         while(no sea fin de cadena){

             símbolo = siguiente carácter de la cadena;
             if(símbolo es un operando)
                   pilaOperandos.push(símbolo);
             else{
                   numero2 = pilaOperandos.pop( );
                   numero1 = pilaOperandos.pop( );
                   resultado = numero1 símbolo numero2;
                   pilaOperandos.push(resultado);
             }
         }
         return pilaOperandos.pop();

Algoritmo de evaluación de una expresión en notación postfija.

   La solución propuesta por el Algoritmo de evaluación de una expresión en notación postfija se basa, como es de esperarse, en una pila. Se deja como ejercicio al lector el análisis y comprensión de dicho algoritmo, así como su correspondiente implementación (consulte la entrada correspondiente a Ejercicios selectos para pilas Java y C++ respectivamente para obtener mayor información).

21 de marzo de 2017

Herencia / Generalización

   Uno de los conceptos del paradigma orientado a objetos más importantes es el de herencia, ya que dicho mecanismo de abstracción permite la re utilización de código de una manera sumamente conveniente, además de habilitar las capacidades del polimorfismo a través de la sobre escritura (override) de métodos.

   Abstracción.
   La ejemplificación del concepto de herencia/generalización estará basada en los Ejemplo Persona y el Ejemplo Cientifico para Java, y en el Ejemplo Herencia para C++; pero antes de poder describirlos, considero pertinente presentar primero en un diagrama de clases los detalles de la relación de generalización que se quiere mostrar con la finalidad de elevar el nivel de abstracción. Con el diagrama de clases propuesto, se pretende llevar el concepto de herencia/generalización a la forma en que la mayoría de las personas comprendemos y analizamos las cosas, para posteriormente profundizar con más conocimiento de causa en los detalles de la implementación de dicho concepto en un lenguaje de programación.

   El diagrama de clases UML (Unified Modeling Language) del que partirá el análisis se muestra en la siguiente figura:
 
Diagrama de clases UML para mostrar la relación de generalización / herencia entre Científico y Persona.

    Los detalles completos de la explicación de un diagrama de clases UML quedan fuera de los alcances de este blog, por lo que sólo se describirán los aspectos más relevantes que ayuden al lector a visualizar de mejor manera, en caso de que el lector no cuente con experiencia en UML, la relación de generalización y herencia.

   Un diagrama de clases UML está compuesto, grosso modo, por clases y las relaciones entre dichas clases. En este sentido, cada clase se representa con un recuadro dividido en tres partes:
  1. Identificador de la clase.
  2. Listado de atributos con la especificación de su clase (tipo) y sus niveles de acceso correspondientes.
  3. Listado de métodos con la especificación de la clase (tipo) de sus argumentos y valor o clase de retorno, así como los niveles de acceso correspondientes para los métodos.
   Tanto para el caso de los atributos como para el de los métodos, los niveles de acceso están representados por un signo de más para un acceso público (+), un signo de menos para un acceso privado (-), y un signo de gato para un nivel de acceso protegido (#).

   Con base en lo anterior, puede observarse de nuestro diagrama que la clase Persona, y por lo tanto las instancias (objetos) que se deriven de ella, tendrán las siguientes características (atributos) comunes a una persona: un nombre, una edad, y una nacionalidad (podrían definirse mucho más características u otras diferentes a las descritas aquí, pero no es la intención del ejemplo representar todas las características completas y comunes a una persona). Observe también que se ha definido un conjunto de operaciones, acciones, responsabilidades o comportamiento comunes a una persona, mismas que se encuentran definidas por los métodos establecidos (al igual que para los atributos, no se ha pretendido modelar por completo el comportamiento o las responsabilidades representadas en los métodos, sino sólo una representación muy general).

   Con base en las aclaraciones previas y lo descrito hasta aquí, es posible decir que una persona promedio está representada de manera muy general por la clase Persona.

   Ahora bien, un científico es (recuerde la idea de división en especializaciones: relación is-a presentada en la entrada Orientación a objetos (conceptos)) una persona, y por lo tanto comparte las características o atributos así como las acciones o el comportamiento inherentes a una persona; y es precisamente este tipo de relación de compartir la que se refiere a la herencia, ya que se dice que en la herencia una clase hereda (comparte) los atributos (características) y métodos (acciones) a otra.

   La herencia en UML se representa por medio de una flecha como la de la figura anterior (diagrama de clases). Es importante señalar que el sentido de la flecha es sumamente significativo, ya que tal y como aparece en nuestra figura, el diagrama indica que la clase Científico hereda las características y el comportamiento de la clase Persona (y no al revés). Otra forma de verlo es que la clase Persona es una generalización de la clase Científico en el sentido de que esta última agrega cierto nivel de especificación respecto de la primera.

   Note también que la clase Científico define un atributo adicional (especialidad), mismo que se añade a todos los atributos que implícitamente ya tiene, mismos que fueron heredados de la clase Persona. Observe también que se han definido cuatro métodos para la clase Científico los cuales tienen las siguientes características:
  1. estableceEspecialidad: es un método de tipo set para el atributo especialidad definido en la clase Científico.
  2. obtenEspecialidad: es un método de tipo get para el atributo especialidad definido en la clase Científico.
  3. mensaje: este método ya estaba definido en la clase Persona, pero al ser redefinido en la clase Científico, se dice que sobre escribe (override) al primero, lo cual significa que un objeto instanciado de la clase Científico, responderá al mensaje mensaje con la definición de su propio método y no con la definición del método mensaje definido en la clase Persona.
  4. mensajeEspecial: este es un nuevo método particular y específico a las instancias derivadas de la clase Científico.
   Es fundamental que el lector se asegure de comprender la descripción hasta aquí realizada respecto a las clases PersonaCientífico. Es también muy importante entender la relación existente entre estas clases antes de continuar a la siguiente sección, en donde entre otras cosas, se abordarán los aspectos relacionados con la implementación de ellas en el lenguaje de programación correspondiente.

13 de febrero de 2017

Programación orientada a objetos.

   En entradas anteriores se discurrió en los elementos fundamentales de la orientación a objetos:
   La intención de dichas entradas es la de proporcionar al lector un panorama general del paradigma orientado a objetos sin asociarlo necesariamente con la programación, y mucho menos con algún lenguaje de programación en particular.

   Un lenguaje de programación es sólo un medio para el paradigma, no el paradigma en sí. Por otro lado, el ejercicio o labor de la programación es la forma de aplicar los conceptos asociados al paradigma.

   Las entradas subsecuentes irán detallando al lector los conceptos presentados pero desde la perspectiva de la programación y su aplicación en algún lenguaje de programación. Sin embargo, es importante aclarar que el objetivo del blog no es enseñar los lenguajes de programación, sino el de utilizarlos como un medio para hacer tangibles los conceptos de orientación a objetos.

   El blog proporciona entradas particulares que introducen a algunos de los aspectos de los lenguajes de programación Java y C++ que podrían ser de utilidad para el lector, pero de ninguna manera pretende cubrir los elementos completos de dichos lenguajes, sino solamente presentar un panorama general:
   Además de lo anterior el blog presenta las bases del paradigma orientado a objetos en el contexto de su aplicación a la programación utilizando al lenguaje de programación Java y C++.

   La intención principal de las entradas que siguen este enfoque que se acaba de mencionar, es la de concretizar en algún lenguaje de programación los conceptos más distintivos del paradigma orientado a objetos, para que en entradas posteriores se puedan aplicar al desarrollo de las estructuras de datos, y mejorar así tanto la comprensión de los conceptos, como la experiencia del lector.


10 de febrero de 2017

Ejercicios selectos (Orientación a objetos).

  1. Investigue más acerca de la historia y desarrollo de la programación orientada a objetos.
  2. Xerox es actualmente una compañía que desarrolla equipo de foto copiado e impresión entre otras cosas. Investigue cuál era el sistema operativo que utilizaban en los años de Xerox PARC (Palo Alto-California Research Center) que por cierto, ya incluía una GUI (Interfaz Gráfica de Usuario) pionera de las GUI que actualmente se utilizan.
  3. Investigue la historia y la ideología del lenguaje de programación Smalltalk. Aproveche para conocer el nombre de su(s) creador(es).
  4. Investigue la historia y la ideología del lenguaje de programación Eiffel. Aproveche para conocer el nombre de su(s) creador(es).
  5. Investigue la historia del lenguaje de programación C++. Aproveche para conocer el nombre de su(s) creador(es).
  6. Investigue el papel del Dr. Alan Curtis Kay en la concepción y desarrollo de la programación orientada a objetos.
  7. Investigue qué otros paradigmas de programación existen.
  8. Investigue qué lenguajes de programación actuales soportan el paradigma orientado a objetos, cuáles lo soportan de manera nativa y cuáles como una extensión.


8 de febrero de 2017

Orientación a objetos y modularidad.

   La modularidad no está exclusivamente relacionada con los procedimientos o funciones de la programación estructurada, sino con el grado en el que los componentes de un sistema pueden ser separados y reutilizados.

   En función de lo anterior, tanto los métodos como los objetos son en sí mismos módulos de una aplicación determinada y en consecuencia, las clases de las que se derivan constituyen los módulos del sistema, por lo que de aquí en adelante se hará referencia a la modularidad de manera indistinta tanto para clases, como para los métodos de las clases.

   La modularidad ayuda también a hacer el código más comprensible, y esto a su vez hace que en consecuencia, al menos en principio, el código sea más fácil de mantener. Sin embargo, sin las debidas y pertinentes consideraciones, la modularidad tiene también sus consecuencias negativas, mismas que están en función directa de dos conceptos fundamentales en el desarrollo de software en general, y en el paradigma orientado a objetos en particular:
  1. Cohesión.
  2. Acoplamiento.
Cohesión y Acoplamiento.
   La cohesión está relacionada con la integridad interna de un módulo. Es el grado o nivel de relación o integridad entre los elementos que componen un módulo.

   El nivel de cohesión determina qué tan fuerte están relacionados cada unos de los elementos de funcionalidad expresados en el código fuente de un módulo.

   Por otro lado, el acoplamiento describe qué tan fuerte un módulo está relacionado con otros, es decir, es el grado en que un módulo depende de cada uno de los otros módulos que componen un sistema.

   El acoplamiento también puede ser referido o entendido como dependencia, lo cual ayuda a recordar que lo que se desea es mantener un bajo nivel de dependencia entre los módulos, es decir un bajo acoplamiento.

   En general, se desea que los módulos de un programa o sistema tengan, un alto nivel de cohesión y un bajo nivel de acoplamiento. El paradigma orientado a objetos persigue y enfatiza dichos objetivos.


3 de febrero de 2017

Paradigma.

   El concepto de paradigma resulta fundamental en la comprensión del paradigma (valga la redundancia) orientado a objetos.

   Antes de proporcionar la definición que se adoptará en el blog, se describirán algunas de las definiciones que existen de paradigma [wordreference]:
  • paradigma m. Ejemplo o ejemplar: esa chica es el paradigma de la paciencia.
  • paradigma ling. Cada uno de los esquemas formales a los que se ajustan las palabras, según sus respectivas flexiones: paradigma de la conjugación verbal.
  • paradigma ling. Conjunto de elementos de una misma clase gramatical que pueden aparecer en un mismo contexto: paradigma de las preposiciones.
  • paradigma ejemplo o modelo. En todo el ámbito científico, religioso u otro contexto epistemológico, el término paradigma puede indicar el concepto de esquema formal de organización, y ser utilizado como sinónimo de marco teórico o conjunto de teorías.
   Pero entonces, ¿qué entender por paradigma de programación?

   La palabra paradigma irrumpió en la ciencia y el vocabulario moderno a través del influyente libro "The Structure of Scientific Revolutions" del historiador de la ciencia Thomas Samuel Kuhn.

   Thomas Kuhn utilizó el término en la forma de la última definición: un paradigma es un modelo para describir un conjunto de teorías, estándares y métodos que en conjunto representan una forma de organizar el conocimiento, esto es, una forma de ver el mundo.
 
   Con base en a lo anterior, a lo largo del blog se entenderá como paradigma de programación al modelo de programación utilizado, el cual está descrito y definido por un conjunto de teorías, estándares y métodos que en conjunto, representan una propuesta de solución por software hacia una problemática determinada.

   Kuhn utilizó la ilusión óptica de la siguiente figura para ilustrar el concepto de paradigma. En dicha figura puede verse un conejo o un pato dependiendo de la perspectiva que se utilice:

Ilusión óptica del conejo-pato creada por Joseph Jastrow.
 
    El paradigma orientado a objetos cambió la perspectiva respecto del enfoque estructurado, el cual era el paradigma dominante hasta entonces.

Una perspectiva diferente.
   El concepto sobre el que subyace la esencia de la orientación a objetos es la abstracción. Por lo que, al pensar en este paradigma, se debería tener en mente una perspectiva basada en los siguientes conceptos:
  1. Entidades: agentes u objetos en interacción, donde cada uno de ellos tiene un rol y características denotadas por atributos.
  2. Responsabilidades: cada objeto proporciona un conjunto de servicios o lleva a cabo acciones que son utilizadas por otras entidades u objetos. Las responsabilidades determinan el comportamiento del objeto.
  3. Mensajes: en la POO la acción es iniciada por la transmisión de un mensaje a un objeto responsable de dicha acción. En respuesta al mensaje, el objeto receptor llevará a cabo un método para satisfacer la solicitud que le fue realizada.
   Los tres elementos anteriormente mencionados constituyen los fundamentos primordiales de la orientación a objetos. A lo largo del blog se desarrollarán de manera progresiva y se ejemplificarán con programas.
 
   Mensajes, procedimientos/funciones y métodos.
   Los mensajes son solicitudes específicas de alguno de los servicios o responsabilidades asignadas a un objeto. Los mensajes tienen un receptor específico, por lo que son enviados a un objeto en particular y pueden contener lista de argumentos.

   Los mensajes son llevados a cabo por métodos, los cuales son algoritmos asociados a un objeto (o a una clase de objetos), cuya ejecución se desencadena tras la recepción de un mensaje. En este sentido, tanto los métodos como los procedimientos o funciones son un conjunto de pasos bien definidos que llevan a cabo una acción; sin embargo, los mensajes y los procedimientos o funciones se distinguen esencialmente por dos aspectos:
  1. En un mensaje hay un receptor designado para dicho mensaje. Las funciones o procedimientos son generales, no hay un receptor específico.
  2. La interpretación o método utilizado para responder al mensaje es determinado por el receptor, y puede variar en función del receptor. Las funciones o procedimientos son únicos tanto en sus identificadores como en sus listas de parámetros.

2 de febrero de 2017

Orientación a Objetos (orígenes).

   Las características principales de lo que actualmente se denomina Programación Orientada a Objetos (POO) surgen en el siglo XX alrededor de 1960; y aunque algunos autores difieren en sus orígenes, comparto la idea de que los conceptos de la POO tienen su inicio en Simula 67, un lenguaje diseñado en el centro de cómputo noruego en Oslo. Simula --dicho sea de paso-- es un lenguaje para simulaciones creado por Ole-Johan Dahl y Kristen Nygaard.

   Posteriormente, en Agosto de 1981, se publica en la revista Byte la descripción del lenguaje de programación Smalltalk, el cual refinó algunos de los conceptos originados con el lenguaje Simula. Smalltalk fue desarrollado en Xerox PARC (Palo Alto-California Research Center).

   Lo anterior dio pie a que en la década de 1980 los lenguajes de programación Orientados a Objetos (OO) tuvieran un rápido auge y expansión, por lo que la POO se fue convirtiendo en el estilo de programación dominante a mediados de los años ochenta del siglo pasado. Con todo, este modelo de programación continúa vigente hasta nuestros días.

   La POO fue una de las primeras propuestas de solución para ayudar a resolver la denominada, aunque no generalmente aceptada, "crisis del software". En este sentido es importante decir que, si bien las técnicas OO pueden facilitar la creación de complejos sistemas de software a través de mecanismos alternativos de abstracción, no son la panacea universal ni las "balas de plata".

   Programar una computadora sigue siendo una de las tareas más difíciles jamás realizadas por un ser humano. Volverse experto en programación requiere, no sólo de saber manejar herramientas y conocer técnicas de programación, sino que además es preciso contar también con:
  • Talento.
  • Creatividad.
  • Ingenio.
  • Lógica.
  • Habilidad para construir y utilizar abstracciones.
  • Experiencia
  • Etcétera.
   Por lo anterior, hacer un uso efectivo de los principios OO requiere de una visión del mundo desde una perspectiva distinta; sobre todo si se parte de la base de resolución de problemas a través de un enfoque estructurado.

   Es importante señalar y tener presente desde este momento, que el uso de un lenguaje de POO no hace, por sí mismo, que se programe OO, ya que se podría tener en el mejor de los casos, un programa o sistema implementado con un enfoque estructurado pero programado en un lenguaje orientado a objetos.
 
   La POO requiere en primera instancia de la comprensión del paradigma orientado a objetos, por lo que se debería iniciar el aprendizaje con un recorrido conceptual partiendo por el concepto de paradigma que se utilizará a lo largo del blog.


27 de enero de 2017

A modo de prefacio.

   Estimado lector, este blog tiene una orientación específica. Está pensado como un curso introductorio de programación orientada a objetos en donde, de manera preferente aunque de ninguna manera obligatoria, se haya tenido un contacto previo con algún lenguaje de programación utilizando el enfoque estructurado; sin embargo, también es mi intención que el blog sea de utilidad para aquellos lectores que se quieran iniciar en el mundo de la programación y el paradigma orientado a objetos sin ningún requisito previo de programación.

   El blog asume que el lector posee conocimientos básicos de algoritmos y/o programación, así como el funcionamiento de las estructuras de control secuencial, de selección, y de repetición. Por otro lado, si bien es cierto que para la comprensión del paradigma no son precisos dichos conocimientos (de hecho podrían generar un vicio para un paradigma de programación orientado a objetos más puro), sí lo son para la comprensión y el seguimiento correspondiente de los programas de ejemplo.

   Con todo, el blog proporciona una entrada para apoyar al lector a través de ejemplos selectos tanto en la introducción del lenguaje de programación utilizado, como en los conceptos fundamentales de la programación.

   Existe desde hace mucho tiempo un debate acerca de si es mejor enseñar el paradigma orientado a objetos sin antes tener un conocimiento de otro enfoque de programación (como el estructurado por ejemplo), o si es mejor partir de la programación estructurada para realizar una transición hacia la programación orientada a objetos. En mi opinión ambos enfoques tienen sus ventajas y desventajas.

   Java es un lenguaje de programación híbrido, en el sentido de que no es un lenguaje totalmente orientado a objetos como Smalltalk, y en ese sentido, tiene estructuras de control y tipos de datos primitivos al estilo del lenguaje de programación C, el cual es el lenguaje por antonomasia para la programación estructurada y, dado que este blog utiliza a Java y C++ como lenguajes de programación, aquellos lectores que conozcan el lenguaje C se sentirán familiarizados rápidamente con Java (e indudablemente con C++) concentrándose entonces en la asimilación del paradigma y en su aplicación.

   Por otro lado, aquellos lectores que no conozcan el enfoque estructurado estarían, al menos de primera instancia, sin la predisposición a cometer uno de los vicios más comunes al programar en el enfoque orientado a objetos, como lo es el de utilizar un lenguaje de programación orientado a objetos, para escribir programas en un enfoque estructurado. En éste sentido, resulta fundamental enfatizar desde ahora que el uso de un lenguaje de programación orientado a objetos no hace per se, ni mucho menos garantiza, que los programas que se escriban en dicho lenguaje sigan el modelo de programación orientado a objetos.

   Como en muchas cosas de la vida y lo cotidiano, más que establecer qué es lo mejor y qué no lo es, ya que se está ante una disyuntiva subjetiva, el beneficio dependerá finalmente tanto de las intenciones del lector como de su disposición hacia la comprensión del paradigma orientado a objetos, así como de que se entienda que la asimilación de un nuevo enfoque de programación no es excluyente de otros, sino que la diversidad de enfoques de solución o formas de resolver un problema, amplían el repertorio de conocimientos, herramientas y capacidades en pro de ser progresiva y eventualmente mejores programadores.

   Para ilustrar y complementar de mejor manera tanto el diseño como los conceptos relacionados con los objetos, el blog se apoya de diagramas de clase UML para su correspondiente representación, por lo que sería también de mucha utilidad poseer bases de dicho lenguaje de modelado; sin embargo, tampoco son indispensables.

   La intención del blog es también la de introducir al lector en algunas de las estructuras de datos más convencionales y al mismo tiempo, utilizarlas para ilustrar los conceptos del paradigma orientado a objetos a través de su implementación.

     Finalmente, insisto en que este blog tiene una naturaleza introductoria pero no por ello informal. Confío plenamente en que puede servir como el inicio de un largo camino en la asimilación progresiva de los conceptos asociados con el paradigma orientado a objetos. Espero sinceramente haber podido alcanzar la meta de transmitir los conceptos fundamentales de la orientación a objetos, así como su aplicación en las estructuras de datos utilizando como medios a los lenguajes de programación Java y C++.