- Considere el Ejemplo HolaEjecutable2. Modifíquelo para que la línea 18 substituya a la 17, recompile y pruebe su funcionamiento. Se recomienda ampliamente al lector consultar el API de Java para documentarse acerca del uso del constructor correspondiente y asegurase de comprender su funcionamiento.
- Considere el Ejemplo HolaHilo2. Integre la línea 17 (que aparece comentada) para que forme parte del código, recompile y pruebe su funcionamiento. Se recomienda ampliamente al lector consultar el API de Java para documentarse acerca del uso del método setName( ) de la clase Thread y asegurase de comprender su funcionamiento; así como de comprender también la similitud y diferencias con respecto al ejercicio anterior.
- Con base en los Ejemplos HolaHilo2 y HolaEjecutable2 realice, para cada uno, lo siguiente:
- Genere más de un hilo (al menos tres) y póngalos en ejecución.
- Genere un arreglo con capacidad para almacenar diez hilos, creé el número de hilos correspondiente y ponga a todos en ejecución.
- Asegúrese de comprender por completo el Ejemplo HilosInteractuando. Posteriormente, modifique el ejemplo para:
- Cambiar los tiempos de método join (línea 67) una vez que haya consultado el API y comprenda más a fondo su funcionamiento.
- Cambiar el nombre del hilo de main, para que en la ejecución, en lugar de ver, por ejemplo "main: Todavía esperando...", sea vea: "Padre: Todavía esperando...".
- Pruebe con argumentos en la invocación del programa para modificar el tiempo de espera (paciencia) del hilo principal (main).
- Considere el Ejemplo PruebaContador. Asegúrese de probar la equivalencia de las líneas 42-43 con la línea 44.
- Para el Ejemplo PruebaContadorSincronizado, asegúrese de probar la equivalencia de las líneas 43-44 con la línea 45.
- En la entrada Sincronización, se hace referencia a que un constructor no puede ser sincronizado. Pruebe dicha situación generando el error de sintaxis que debería generarse.
- Considere y analice el Ejemplo MsLunch. Asegúrese de comprender la diferencia entre éste y las distintas versiones del ejemplo comentado en la entrada Sincronización.
- Con base en las entradas Creación de hilos, Sincronización y los ejemplos correspondientes, escriba un programa que realice lo siguiente:
- Genere 6 hilos: 3 utilizando Thread y 3 utilizando Runnable.
- Cada hilo deberá incrementar 100 000 veces el valor de un contador compartido e imprimir su valor al finalizar.
- El hilo principal (main) deberá decrementar 600 000 veces el valor del contador compartido e imprimir su valor al finalizar.
- El hilo principal deberá, antes de iniciar sus decrementos, esperar (join) a cada hilo 50 milisegundos.
- El hilo principal deberá llamarse padre y los hilos creados: hijo1, hijo2, ... hijo 6.
- ¿Cuál debería ser el valor final del contador en un enfoque sincronizado y por qué?
- Para el Ejemplo Interbloqueo, elimine la palabra reservada synchronized de ambos métodos ¿Que piensa que sucederá y por qué? Determine su respuesta antes de volver a compilar y ejecutar.
- Considere, analice y comprenda el Ejemplo Interbloqueo2 sin ejecutarlo.
- ¿Puede determinar lo que hace?
- ¿Se comprende la diferencia con el Ejemplo Interbloqueo?
- ¿Por qué hace lo que hace?
Se presentan los principales conceptos y fundamentos del Paradigma y de la Programación Orientada a Objetos (POO), así como una aplicación a las Estructuras de Datos más comunes: Pilas, Colas, Listas y Árboles binarios. También se proporciona una introducción a la programación concurrente, la comunicación por sockets y el manejo de excepciones.
Mostrando las entradas con la etiqueta Interfaz. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Interfaz. Mostrar todas las entradas
1 de enero de 2021
Ejercicios selectos (Hilos).
11 de mayo de 2018
Características fundamentales de la POO.
Alan Curtis Kay, quien es considerado por muchos (yo entre ellos) como el padre de la POO, definió un conjunto de características fundamentales para el paradigma orientado a objetos.
Con base en lo propuesto por Kay, en la Programación Orientada a Objetos:
- Todo es un objeto.
- El procesamiento es llevado a cabo por objetos:
- Los objetos se comunican unos con otros solicitando que se lleven a cabo determinadas acciones.
- Los objetos se comunican enviando y recibiendo mensajes.
- Un mensaje es la solicitud de una acción, la cual incluye los argumentos que son necesarios para completar la tarea.
- Cada objeto tiene su propia memoria, misma que está compuesta de otros objetos.
- Cada objeto es una instancia de una clase. Una clase representa un grupo de objetos similares.
- La clase es el repositorio del comportamiento asociado con un objeto.
- Todos los objetos que son instancias de la misma clase llevan a cabo las mismas acciones.
- Las clases están organizadas en una estructura jerárquica de árbol denominada jerarquía de herencia.
- La memoria y el comportamiento asociados con las instancias de una clase, están automáticamente disponibles para cualquier clase asociada con la descendencia dentro de la estructura jerárquica de árbol.
En un intento de complementar la visión de Alan Kay, se presenta a continuación un compendio de conceptos que definen también y refuerzan las características principales de la POO:
- La abstracción denota las características esenciales de un objeto.
- El proceso de abstracción permite seleccionar las características relevantes del objeto dentro de un conjunto e identificar comportamientos comunes para definir nuevos tipos de entidades.
- La abstracción es la consideración aislada de las cualidades esenciales de un objeto en su pura esencia o noción.
- La modularidad es la propiedad que permite subdividir una aplicación en partes más pequeñas (llamadas módulos), cada una de las cuales debe ser tan independiente como sea posible de la aplicación en sí, y de las partes restantes.
- La modularidad es el grado en el que los componentes de un sistema pueden ser separados y reutilizados.
- El encapsulamiento tiene que ver con reunir todos los elementos que pueden considerarse pertenecientes a una misma entidad al mismo nivel de abstracción. Esto permite aumentar la cohesión de los módulos o componentes del sistema. La encapsulación es quizá el concepto más importante del paradigma, ya que permite agrupar las funcionalidades (métodos) y el estado (datos) de los objetos de forma cohesiva. Los métodos proporcionarán los mecanismos adecuados para modificar el estado, y en algunos casos también serán la puerta de acceso a éste.
- El principio de ocultación de información (information hiding) se refiere a que cada objeto está aislado del exterior; es un módulo independiente y cada tipo de objeto presenta una interfaz a otros objetos, la cual especifica cómo es que pueden interactuar con él.
- El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas; solamente los propios métodos internos del objeto pueden acceder a su estado. Lo anterior asegura que otros objetos no puedan cambiar el estado interno de un objeto de manera accidental o intencionada, eliminando así efectos secundarios e interacciones inesperadas.
- El polimorfismo está relacionado con el aspecto referente al de qué tipo de comportamientos diferentes asociados a objetos distintos, pueden compartir el mismo nombre.
- El polimorfismo es la capacidad que tienen los objetos de naturaleza heterogénea, de responder de manera diferente a un mismo mensaje en función de las características y responsabilidades del objeto que recibe dicho mensaje.
- La herencia organiza y facilita el polimorfismo y el encapsulamiento, permitiendo a los objetos ser definidos y creados como tipos especializados de objetos preexistentes.
- Las clases no están aisladas, sino que se relacionan entre sí formando una jerarquía de clasificación.
- Los objetos heredan las propiedades y el comportamiento de todas las clases a las que pertenecen. Así, los objetos pueden compartir y extender su comportamiento sin tener que volver a implementarlo.
- La herencia múltiple se da cuando un objeto hereda de más de una clase.
Es sumamente importante en lo subsecuente, tener todos estos conceptos vigentes y presentes, estudiarlos, analizarlos y comprenderlos; la memorización no es recomendable, ya que el memorizar conceptos no implica necesariamente su asimilación y mucho menos su comprensión. Por otro lado, si un concepto es comprendido, es posible entonces el poder explicarlo y deducir en consecuencia su definición.
Mi deseo es que el lector reflexione sobre este aspecto y que, con un poco de paciencia, sume a su repertorio de conocimientos el conjunto de conceptos descritos hasta aquí, los cuales se pondrán en práctica eventual y progresivamente en entradas subsecuentes del blog.
Mi deseo es que el lector reflexione sobre este aspecto y que, con un poco de paciencia, sume a su repertorio de conocimientos el conjunto de conceptos descritos hasta aquí, los cuales se pondrán en práctica eventual y progresivamente en entradas subsecuentes del blog.
Etiquetas:
Abstracción,
Alan Kay,
Clase,
Cohesión,
Comportamiento,
Encapsulamiento,
Herencia,
Information hiding,
Instancia,
Interfaz,
Métodos,
Modularidad,
OO,
Polimorfismo,
POO
8 de mayo de 2017
Herencia vs. composición (listas).
Uno de los aspectos más importantes de la programación orientada a objetos es la conveniencia de la reutilización de código por medio de la abstracción. En este sentido, dos de los esquemas más comunes al respecto son: la herencia y la composición.
Esta entrada muestra, por medio de un ejemplo ya conocido y presentado previamente al lector, la implementación de una pila utilizando una lista enlazada. Dicha implementación se realiza empleando los dos esquemas mencionados con anterioridad. Así mismo, se analizan las ventajas y desventajas de cada uno de ellos.
Esta entrada muestra, por medio de un ejemplo ya conocido y presentado previamente al lector, la implementación de una pila utilizando una lista enlazada. Dicha implementación se realiza empleando los dos esquemas mencionados con anterioridad. Así mismo, se analizan las ventajas y desventajas de cada uno de ellos.
Implementación de una pila utilizando herencia.
La implementación de una pila por medio de una lista con un enfoque basado en la herencia es en realidad bastante simple. Para muestra, basta con ver el código del código del Ejemplo PilaH.
Observe que la clase del Ejemplo PilaH no define atributos, y que únicamente define dos constructores y los métodos push y pop; lo cual también ha sido representado en el diagrama de clases UML de la siguiente figura.
Observe que la clase del Ejemplo PilaH no define atributos, y que únicamente define dos constructores y los métodos push y pop; lo cual también ha sido representado en el diagrama de clases UML de la siguiente figura.
Insto nueva y amablemente al lector a que compare, contraste, y analice con detenimiento antes de continuar, a la figura anterior con el Ejemplo PilaH.
Note que los métodos push (líneas 14-16) y pop (líneas 18-20) del Ejemplo PilaH no hacen otra cosa más que encapsular el comportamiento de los métodos insertaAlInicio y eliminaDelInicio respectivamente, los cuales son servicios o comportamiento definidos en la clase Lista del Ejemplo Lista. Note también que es posible acceder a dichos métodos debido a que la clase PilaH hereda de la clase Lista (línea 5).
Observe que como parte del mecanismo de la herencia, tampoco es necesario definir el comportamiento de los métodos estaVacia e imprime dentro de la clase PilaH, ya que se encuentran definidos en la clase Lista.
Note que los métodos push (líneas 14-16) y pop (líneas 18-20) del Ejemplo PilaH no hacen otra cosa más que encapsular el comportamiento de los métodos insertaAlInicio y eliminaDelInicio respectivamente, los cuales son servicios o comportamiento definidos en la clase Lista del Ejemplo Lista. Note también que es posible acceder a dichos métodos debido a que la clase PilaH hereda de la clase Lista (línea 5).
Observe que como parte del mecanismo de la herencia, tampoco es necesario definir el comportamiento de los métodos estaVacia e imprime dentro de la clase PilaH, ya que se encuentran definidos en la clase Lista.
El primero de dichos comportamientos forma parte de la definición de las primitivas de la estructura de datos pila, mientras que el segundo es utilizado en la clase PruebaPilaH del Ejemplo PruebaPilaH (líneas 11 y 20), la cual es la clase de prueba del Ejemplo en cuestión.
La salida del Ejemplo PruebaPilaH se muestra en la siguiente figura:
La salida del Ejemplo PruebaPilaH se muestra en la siguiente figura:
Consideraciones.
Al menos en apariencia, el mecanismo de la herencia resulta sumamente conveniente con base en lo expuesto con anterioridad; sin embargo, presenta algunos inconvenientes potenciales que vale la pena considerar.
Las instancias de la clase PilaH, al heredar las características y el comportamiento inherentes a una lista enlazada, pueden hacer uso de los métodos de inserción y de eliminación correspondientes a ésta, por lo que desde esta perspectiva, un objeto de dicha clase podría permitir inserciones y eliminaciones, no únicamente del tope de la pila (representado por inicio), sino también de la base de la pila ("representada" por fin) a la que se supone, por definición de pila, no se debe tener acceso.
Tome en consideración que todavía se podría transgredir más la definición de una pila, ya que potencialmente es posible también insertar en, o eliminar de cualquier parte de la estructura de datos con las modificaciones correspondientes (vea el Ejercicio 2.2 de los Ejercicios selectos), lo cual queda completamente fuera tanto de la definición que se hizo de la pila, como de las operaciones primitivas que le son inherentes.
Las instancias de la clase PilaH, al heredar las características y el comportamiento inherentes a una lista enlazada, pueden hacer uso de los métodos de inserción y de eliminación correspondientes a ésta, por lo que desde esta perspectiva, un objeto de dicha clase podría permitir inserciones y eliminaciones, no únicamente del tope de la pila (representado por inicio), sino también de la base de la pila ("representada" por fin) a la que se supone, por definición de pila, no se debe tener acceso.
Tome en consideración que todavía se podría transgredir más la definición de una pila, ya que potencialmente es posible también insertar en, o eliminar de cualquier parte de la estructura de datos con las modificaciones correspondientes (vea el Ejercicio 2.2 de los Ejercicios selectos), lo cual queda completamente fuera tanto de la definición que se hizo de la pila, como de las operaciones primitivas que le son inherentes.
Implementación de una pila utilizando composición.
La implementación de una pila utilizando el enfoque de composición, se basa en la idea de que una lista enlazada contiene ya definidas las operaciones que necesita una pila, pero que también, como se discutió con anterioridad, contiene otras operaciones que no deberían ser utilizadas por la misma.
En función de lo anterior y de manera conveniente, lo que puede hacerse es encapsular las operaciones de la lista enlazada dentro de las de la pila con la finalidad de proporcionar una interfaz o un conjunto de servicios ad hoc con la definición de la estructura de datos en cuestión: la pila.
En función de lo anterior y de manera conveniente, lo que puede hacerse es encapsular las operaciones de la lista enlazada dentro de las de la pila con la finalidad de proporcionar una interfaz o un conjunto de servicios ad hoc con la definición de la estructura de datos en cuestión: la pila.
![]() |
| Diagrama de clases UML para la implementación de una pila utilizando composición y una lista enlazada. |
La figura anterior muestra el diseño en diagrama de clases UML la definición de una pila que utiliza o contiene (has-a) una lista enlazada para su implementación. Observe y compare con detenimiento dicho diagrama con el respectivo diagrama UML para la implementación con herencia, y note que el cambio principal está en la clase PilaC y en la relación entre ésta y la clase Lista.
Ahora bien, la definición de la clase PilaC se muestra en el Ejemplo PilaC. Insto una vez más al lector a que ponga atención en dos aspectos:
Ahora bien, la definición de la clase PilaC se muestra en el Ejemplo PilaC. Insto una vez más al lector a que ponga atención en dos aspectos:
- La relación entre el diagrama de clases de la figura anterior y el Ejemplo PilaC.
- Los métodos push (líneas 16-18), pop (líneas 20-22) e imprime (líneas 24-26) no hacen otra cosa más que encapsular de manera conveniente, los mensajes enviados al objeto tope (línea 6), mismos que son llevados a cabo por los métodos correspondientes definidos en la clase Lista.
La clase de prueba del Ejemplo PilaC se muestra en el Ejemplo PruebaPilaC y sigue el mismo mecanismo de inserción que el los ejemplos de prueba anteriores. Finalmente, compruebe que la salida del Ejemplo PruebaPilaC coincide exactamente con la salida correspondiente del Ejemplo PruebaPilaH, y que desde el punto de vista de la ejecución, no podría saberse cuál fue el enfoque de diseño elegido.
25 de abril de 2017
Consideraciones adicionales (colas).
Las colas de espera, y las colas de prioridad ascendentes y descendentes tienen amplias y muy variadas aplicaciones, que van desde la simulación y modelado de situaciones relacionadas con las líneas de espera que hacemos todos los días (bancos, boletos, casetas de cobro, etc.), hasta aspectos de bajo nivel relacionado con el funcionamiento de los sistemas operativos por ejemplo.
Las colas de prioridad son un ejemplo sumamente claro en el que la definición de la estructura de datos o ADT es independiente de la implementación, debido a que es posible implementar una cola de prioridad por ejemplo, de al menos dos maneras o enfoques posibles.
La introducción hacia las relaciones de orden en los objetos por medio de la interfaz Comparable presentada en la entrada de Colas de prioridad (Java) resultará fundamental para las entradas siguientes, por lo que se invita al lector a estudiar detenidamente estos conceptos y complementarlos con información adicional como ejercicio y labor de investigación.
Las colas de prioridad son un ejemplo sumamente claro en el que la definición de la estructura de datos o ADT es independiente de la implementación, debido a que es posible implementar una cola de prioridad por ejemplo, de al menos dos maneras o enfoques posibles.
La introducción hacia las relaciones de orden en los objetos por medio de la interfaz Comparable presentada en la entrada de Colas de prioridad (Java) resultará fundamental para las entradas siguientes, por lo que se invita al lector a estudiar detenidamente estos conceptos y complementarlos con información adicional como ejercicio y labor de investigación.
Por otro lado pero en directa correspondencia con las relaciones de orden se proporcionan adicionalmente, para los lectores interesados en desarrollar sus habilidades en C++, dos ejemplos que podrían ser útiles para el desarrollo de los ejercicios propuestos. El primero de ellos tiene que ver con la implementación de operadores, que en el lenguaje en cuestión se denomina sobrecarga de operadores. Ambos ejemplos se basan en un ejemplo previo estudiado con anterioridad en el tema correspondiente a la implementación de la herencia, por lo que sería recomendable echarle antes un vistazo. El segundo ejemplo muestra el funcionamiento de la sobre carga de operadores en la herencia. Se insta al lector a analizarlos, comprender las diferencias y el resultado de la ejecución, con la finalidad de que le sirvan como base para el desarrollo de los ejercicios.
Finalmente, resulta sumamente importante que el lector se tome el tiempo para la realización de los ejercicios propuestos, los cuales tienen, como todos los ejercicios del blog, la finalidad de reforzar, ampliar, desarrollar y poner en práctica tanto los conceptos como los conocimientos adquiridos. Le auguro éxito.
21 de abril de 2017
Colas de prioridad.
La cola de prioridad es una estructura de datos en la que el ordenamiento intrínseco de los elementos, determina el resultado de la aplicación de sus operaciones básicas o primitivas.
En este sentido, existen dos tipos de colas de prioridad:
En este sentido, existen dos tipos de colas de prioridad:
- Cola de prioridad ascendente.
- Cola de prioridad descendente.
Ambas estructuras de datos redefinen la forma de operación convencional respecto de una cola de espera, por lo que serán estudiadas de manera separada.
Cola de prioridad ascendente.
La cola de prioridad ascendente es un tipo de estructura de datos en el que la inserción de los elementos se realiza de manera convencional, pero la eliminación se realiza en base al menor de los elementos almacenados en ella. Para que ésto sea posible, los elementos que almacena la estructura de datos deben tener una relación de orden; es decir, deben poseer algún mecanismo que permita compararlos entre sí.
La siguiente figura muestra la relación de clases en UML para una cola de prioridad ascendente con la redefinición o sobre escritura (override) del método elimina. Observe cómo se ha instrumentado la redefinición de dicho método por medio del mecanismo de la herencia, y que las relaciones previamente existentes se conservan (compare con el diagrama de clases presentado para las colas de espera en la entrada Colas de espera (definición)).
La siguiente figura muestra la relación de clases en UML para una cola de prioridad ascendente con la redefinición o sobre escritura (override) del método elimina. Observe cómo se ha instrumentado la redefinición de dicho método por medio del mecanismo de la herencia, y que las relaciones previamente existentes se conservan (compare con el diagrama de clases presentado para las colas de espera en la entrada Colas de espera (definición)).
![]() |
| Diagrama de clases UML para una cola de prioridad ascendente con la redefinición (override) del método elimina. |
Otro tipo de representación para la cola de prioridad ascendente, consiste en mantener ordenados los elementos de manera ascendente durante la inserción y conservar la operación de eliminación de la forma convencional. Dicha representación se expresa en UML como se muestra en la siguiente figura:
![]() |
| Diagrama de clases UML para una cola de prioridad ascendente con la redefinición (override) del método inserta. |
En resumen, en una cola de prioridad ascendente los elementos se recuperan (eliminan) en orden ascendente respecto de la relación de orden que guarden entre sí. Ahora bien, para objetos con una relación de orden inherente a ellos, como un objeto de la clase Integer o de la clase Float por ejemplo, la comparación es posible pero, ¿qué ocurre con objetos de la clase String del API de Java, o con las clases Persona y Cientifico definidas en la entrada POO (herencia) por ejemplo?
Implementación.
En la orientación a objetos existe un concepto relacionado con la herencia: la herencia múltiple. La herencia múltiple básicamente es la capacidad de una clase de heredar los atributos y métodos de más de una clase; sin embargo, el lenguaje de programación Java no incluye en su gramática dicha capacidad, aunque por otro lado, incorpora un mecanismo que permite que una clase se comprometa, a través de una especie de contrato, a implementar en métodos las operaciones declaradas o establecidas en una interfaz (interface). La interfaz Comparable del API de Java compromete u obliga a las clases que la implementan, a establecer una relación de orden entre los objetos que la implementen. Dicha relación de orden es arbitraria y está en función únicamente del interés o de las necesidades específicas de la clase en cuestión.
Para ilustrar lo anterior, considere el Ejemplo ColaAscendente el cual implementa una cola de prioridad ascendente sobre escribiendo o redefiniendo (override) el método inserta tal y como se propone en el diagrama de clases UML de la figura anterior. Note el uso de la interfaz Comparable. Observe con detenimiento la línea 6 la cual, en el contexto de lo anterior, podría interpretarse de la siguiente manera:
Para ilustrar lo anterior, considere el Ejemplo ColaAscendente el cual implementa una cola de prioridad ascendente sobre escribiendo o redefiniendo (override) el método inserta tal y como se propone en el diagrama de clases UML de la figura anterior. Note el uso de la interfaz Comparable. Observe con detenimiento la línea 6 la cual, en el contexto de lo anterior, podría interpretarse de la siguiente manera:
La clase ColaAscendente es una subclase, clase hija o clase derivada de la clase Cola, gestiona objetos genéricos T que definan o establezcan una relación de orden a través de la implementación del método compareTo declarado en la interfaz Comparable.
Observe que el mensaje o la invocación del método compareTo ocurre en la línea 21 del Ejemplo ColaAscendente, y que la idea general del método inserta (líneas 15-35) consiste en recorrer la secuencia de nodos (líneas 21-24) mientras haya nodos por procesar y no se haya encontrado el lugar correspondiente para el elemento a insertar (línea 21). En este sentido, el método compareTo compara el objeto receptor del mensaje con el objeto proporcionado como argumento; dicho método regresa uno de tres posibles valores (consulte en el API de Java la interfaz Comparable para ampliar y complementar la información al respecto):
- Un entero negativo (< 0) si el objeto receptor del mensaje es menor que el objeto proporcionado como argumento.
- Cero (0) si el objeto que recibe el mensaje es igual al objeto proporcionado como argumento.
- Un entero positivo (> 0) si el objeto receptor del mensaje es mayor que el objeto proporcionado como argumento.
Es importante que el lector comprenda que el método compareTo es definido en la clase que quiera establecer una relación de orden para sus objetos, es decir, los objetos de la clase genérica T deberán tener la definición (código) de dicho método.
Continuando con la explicación del método inserta del Ejemplo ColaAscendente, note que el método hace uso de objetos auxiliares (líneas 16, 18 y 19), para poder realizar el ajuste de las referencias correspondientes en las líneas 26-34. Aquí cabe mencionar que, aunque dichos objetos pudieron haber sido definidos como atributos de la clase ColaAscendente, en realidad no representan una característica o cualidad inherente a los objetos que se deriven de dicha clase, sino que más bien son entidades útiles para la manipulación de la estructura de datos dentro del método, por lo que de ser atributos, aunque la implementación trabajaría de la misma manera, el enfoque sería inapropiado, esto es: sería un diseño inadecuado. El análisis y los detalles del ajuste de las referencias de las líneas 22-23 y 26-34 se dejan como ejercicio para el lector, a quien se insta amablemente a comprender completamente su funcionamiento antes de continuar.
Continuando con la explicación del método inserta del Ejemplo ColaAscendente, note que el método hace uso de objetos auxiliares (líneas 16, 18 y 19), para poder realizar el ajuste de las referencias correspondientes en las líneas 26-34. Aquí cabe mencionar que, aunque dichos objetos pudieron haber sido definidos como atributos de la clase ColaAscendente, en realidad no representan una característica o cualidad inherente a los objetos que se deriven de dicha clase, sino que más bien son entidades útiles para la manipulación de la estructura de datos dentro del método, por lo que de ser atributos, aunque la implementación trabajaría de la misma manera, el enfoque sería inapropiado, esto es: sería un diseño inadecuado. El análisis y los detalles del ajuste de las referencias de las líneas 22-23 y 26-34 se dejan como ejercicio para el lector, a quien se insta amablemente a comprender completamente su funcionamiento antes de continuar.
Por último, la clase de prueba para la cola de prioridad ascendente del Ejemplo ColaAscendente se muestra en el Ejemplo PruebaColaAscendente.
Tómese el lector el tiempo que considere necesario para comparar el Ejemplo PruebaColaAscendente con el Ejemplo PruebaCola y advierta que son, esencialmente iguales.
Note también que los objetos a almacenar en la cola de prioridad ascendente son objetos de la clase Integer (línea 6) por lo que, para que no haya ningún problema en la compilación, dicha clase deberá tener la implementación (implements) de la interfaz Comparable, y en consecuencia, la definición del método compareTo. En este sentido, se invita al lector para que realice dicha comprobación en el API de Java antes de compilar y ejecutar el Ejemplo PruebaColaAscendente.
Tómese el lector el tiempo que considere necesario para comparar el Ejemplo PruebaColaAscendente con el Ejemplo PruebaCola y advierta que son, esencialmente iguales.
Note también que los objetos a almacenar en la cola de prioridad ascendente son objetos de la clase Integer (línea 6) por lo que, para que no haya ningún problema en la compilación, dicha clase deberá tener la implementación (implements) de la interfaz Comparable, y en consecuencia, la definición del método compareTo. En este sentido, se invita al lector para que realice dicha comprobación en el API de Java antes de compilar y ejecutar el Ejemplo PruebaColaAscendente.
Con base en lo anterior, todos los objetos que se deseen almacenar en la cola de prioridad ascendente definida en el Ejemplo ColaAscendente, deberán implementar dicha interfaz, así como definir el comportamiento requerido (código) por el método compareTo.
Por último, observe que a diferencia del Ejemplo PruebaCola, el Ejemplo PruebaColaAscendente inserta intencionalmente nueve números de manera desordenada, ya que la implementación de cola de prioridad propuesta (Ejemplo ColaAscendente) los mantiene ordenados dentro de la estructura de datos, mientras que la eliminación (líneas 18-26) se realiza de manera convencional. La salida del Ejemplo PruebaColaAscendente se muestra en la siguiente figura:
Por último, observe que a diferencia del Ejemplo PruebaCola, el Ejemplo PruebaColaAscendente inserta intencionalmente nueve números de manera desordenada, ya que la implementación de cola de prioridad propuesta (Ejemplo ColaAscendente) los mantiene ordenados dentro de la estructura de datos, mientras que la eliminación (líneas 18-26) se realiza de manera convencional. La salida del Ejemplo PruebaColaAscendente se muestra en la siguiente figura:
Cola de prioridad descendente.
La cola de prioridad descendente es análoga en lo general a la cola de prioridad ascendente.
La cola de prioridad descendente es un tipo de estructura de datos en el que la inserción de los elementos se realiza también de la manera convencional, pero la eliminación se realiza en base al mayor de los elementos almacenados en ella. Al igual que para la cola de prioridad ascendente, para que ésto último sea posible, es necesario que los elementos que almacena la estructura de datos tengan una relación de orden, es decir, es preciso que incorporen algún mecanismo que les permita compararlos entre sí.
La siguiente figura muestra la relación de clases en UML para una cola de prioridad descendente con la redefinición o sobre escritura (override) del método elimina. Una vez más, note cómo se ha instrumentado la redefinición de dicho método por medio del mecanismo de la herencia, y que las relaciones (compare con el diagrama de clases presentado para las colas de espera en la entrada Colas de espera (definición)) previamente existentes se conservan.
La cola de prioridad descendente es un tipo de estructura de datos en el que la inserción de los elementos se realiza también de la manera convencional, pero la eliminación se realiza en base al mayor de los elementos almacenados en ella. Al igual que para la cola de prioridad ascendente, para que ésto último sea posible, es necesario que los elementos que almacena la estructura de datos tengan una relación de orden, es decir, es preciso que incorporen algún mecanismo que les permita compararlos entre sí.
La siguiente figura muestra la relación de clases en UML para una cola de prioridad descendente con la redefinición o sobre escritura (override) del método elimina. Una vez más, note cómo se ha instrumentado la redefinición de dicho método por medio del mecanismo de la herencia, y que las relaciones (compare con el diagrama de clases presentado para las colas de espera en la entrada Colas de espera (definición)) previamente existentes se conservan.
![]() |
| Diagrama de clases UML para una cola de prioridad descendente con la redefinición (override) del método elimina. |
Al igual que para la cola de prioridad ascendente, otro tipo de representación para la cola de prioridad descendente consiste en mantener ordenados los elementos de manera descendente durante la inserción y conservar la operación de eliminación de la forma convencional, tal y como lo sugiere la representación del diagrama de clases UML de la siguiente figura:
![]() |
| Diagrama de clases UML para una cola de prioridad descendente con la redefinición (override) del método inserta. |
Por último, recuerde que en una cola de prioridad descendente los elementos se recuperan (eliminan) en orden descendente respecto de la relación de orden que guardan entre sí. Los detalles de la implementación, se dejan como ejercicio para el lector.
Ejercicios selectos (colas).
![]() |
| (a) Estado inicial para la representación de Round robin. |
![]() |
| (b) Estado siguiente para la representación de Round robin. |
- En el Ejemplo Cola el método inserta tiene la línea 24 como comentario ¿Qué sucede si sustituye la línea 25 por la línea 24? ¿Compilará? Si sí, ¿por qué?, y si no, ¿por qué? Si compila ¿Cuál será el resultado de la ejecución? Determine sus respuestas y después corrobore las mismas con la experimentación.
- En el Ejemplo PruebaCola se creó una cola de espera utilizando un constructor sin argumentos. Modifique dicho ejemplo para asignar un nuevo nombre a la cola por medio del constructor correspondiente, asígnele el nombre de "Mi primera cola de espera", recompile, y pruebe su funcionamiento.
- Modifique el Ejemplo PruebaCola para que permita leer n números enteros desde la entrada estándar y los almacene en la cola de espera.
- Modifique el Ejemplo Cola para que:
- Agregue el método peek a la implementación. Dicha operación funciona de la siguiente manera: echa un vistazo al elemento que se encuentra en el inicio de la cola de espera, lo regresa pero no lo elimina.
- Incorpore un atributo privado numérico (n) que lleve el control del número de elementos insertados en la cola de espera. Al respecto no olvide:
- Inicializar explícitamente dicho atributo a cero en el constructor.
- Proporcionar únicamente el método de tipo get para el atributo n: public int obtenN( ).
- Tomando como referencia el Ejemplo PruebaCola, modifíquelo para que la cola de espera del Ejemplo Cola almacene otro tipo de objetos además de los de la clase Integer. Pruebe con al menos las siguientes clases:
- Double.
- String.
- Persona (del Ejemplo Persona).
- Cientifico (del Ejemplo Cientifico).
- Utilizando una cola de espera como la del Ejemplo Cola, implemente el algoritmo de Round robin. Round robin es un método para seleccionar a todos los elementos en un grupo de manera equitativa y en orden, se comienza con el primer elemento de la cola de espera y se procesa, se continua con el segundo y así de manera progresiva hasta llegar al último elemento de la cola, para empezar nuevamente desde el primer elemento. El principio general subyacente detrás del método, consiste en que cada elemento de la cola de espera consume una parte de un elemento compartido en cantidades iguales.
- Considere la figura anterior en su inciso (a), la cual representa el estado inicial de una cola de espera de números enteros que representan las cantidades a considerar (quantum).
- El estado siguiente (inciso (b)) consiste en atender (restarle uno al quantum) al nodo que se encuentra al inicio de la cola y volverlo a formar al final de la misma para atender de manera análoga a los siguientes nodos.
- Tome en consideración que, una vez que el número llega a cero, el nodo correspondientes es eliminado.
- El proceso anteriormente descrito continúa hasta atender o despachar a todos los nodos formados en la cola. Para ello:
- Genere un número aleatorio entre 10 y 50, el cual representará el número de nodos que contendrá la cola de espera.
- Por cada nodo, genere nuevamente un número aleatorio entre 1 y 500, mismo que representará el quantum asignado a cada nodo.
- No olvide construir también una clase de prueba para su implementación. La salida de su programa puede ser en la salida estándar o en un archivo de texto (consulte el API). Es importante que compruebe el adecuado funcionamiento de su implementación, ya que se reutilizará en otros ejercicios del blog.
- Modifique el Ejemplo PruebaColaAscendente para que la cola de prioridad ascendente del Ejemplo ColaAscendente almacene otro tipo de objetos además de los de la clase Integer. Pruebe con al menos las siguientes clases:
- Double.
- String.
- Persona (del Ejemplo Persona).
- Cientifico (del Ejemplo Cientifico).
- Tome en cuenta que las clases Double y String del API de Java implementan la interfaz Comparable, pero que las clases Persona y Cientifico no, por lo que como primer paso, deberá hacer que dichas clases implementen la interfaz Comparable y definan el método compareTo. Para ello:
- Realice el ordenamiento en base al atributo que representa la edad de la persona para las instancias de la clase Persona (vea 7.6).
- Realice el ordenamiento en función del atributo que representa la especialidad del científico para las instancias de la clase Cientifico (vea 7.7).
- Como guía adicional para el lector, la clase PersonaComparable del Ejemplo PersonaComparable realiza la implementación de la interfaz Comparable. Observe cómo dicho ejemplo es esencialmente igual al Ejemplo Persona. Compare ambos ejemplos, estúdielos, y ponga especial atención en las líneas 5 y 57-63 del Ejemplo PersonaComparable, para que pueda resolver lo planteado en este ejercicio.
- Respecto a la clase Cientifico, la solución es un poco más elaborada:
- Si partimos de la siguiente base: public class Persona implements Comparable<Persona>{...}. Entonces la herencia debería ser: public class Cientifico extends Persona implements Comparable<Persona>{...} y no public class Cientifico extends Persona implements Comparable<Cientifico>{...} ya que de otra forma el compilador indicará que Comparable no puede ser heredada con diferentes argumentos (Cientifico y Persona).
- El método compareTo de Cientifico debe hacer un cast (conversión de tipos): public int compareTo(Persona p){ Cientifico c = (Cientifico) p; // aquí va el código que compara con los criterios para Científico.}.
- La cola ascedente deberá indicar que almacena objetos de la clase base Persona: ColaAscendente<Persona> cola = new ColaAscendente<Persona>( ); pero insertar instancias de Cientifico (por eso es necesario el cast).
- En este tipo de problemas recuerde siempre usar la clase base como tipo base para los datos, aunque inserte objetos de clases derivadas. El proceso de eliminación es equivalente.
- Con base en las consideraciones hechas en el blog respecto de la cola de prioridad ascendente y al diseño propuesto por el diagrama de clases UML alternativo (entrada Colas de prioridad), realice la implementación de la cola de prioridad ascendente sobrescribiendo ahora el método elimina. Pruebe su propuesta con las clases y las consideraciones hechas en el Ejercicio anterior para la interfaz Comparable.
- Realice la implementación de una cola de prioridad descendente de manera análoga a la del Ejemplo ColaAscendente. Para lo anterior, tome en cuenta las consideraciones hechas en el blog y lo expuesto en el diseño representado por el diagrama de clases UML (entrada Colas de prioridad). No olvide definir también la clase de prueba para verificar y validar su propuesta; puede basarse en la del Ejemplo PruebaColaAscendente. Para sus pruebas, tome en cuenta al menos, las clases y consideraciones propuestas en el Ejercicio 7.
- Con base en las consideraciones hechas en el blog respecto de la cola de prioridad descendente y al diseño propuesto por el diagrama de clases UML alternativo (entrada Colas de prioridad), realice la implementación de la cola de prioridad descendente. Pruebe su propuesta con las clases y las consideraciones hechas en el Ejercicio 7 para la interfaz Comparable.
- Considere la abstracción de la estructura de datos compuesta mostrada en la figura que aparece al final de esta entrada. La estructura de datos mostrada está compuesta por una cola de espera y varias pilas, una por cada nodo formado en la cola. Note que cada nodo de la cola de espera conserva una referencia a objetos como él, y una referencia a objetos de tipo pila. Este ejercicio consiste en hacer una representación de una fila de supermercado, en donde cada nodo formado en la cola de espera, simula un carrito de supermercado con diferentes productos almacenados en él en forma de pila (en la vida real no necesariamente es así, pero para el caso del ejercicio propuesto basta con esa suposición). Cada nodo de la pila representa un producto, por lo que se requiere que la información que almacena la pila sean cadenas que representan la descripción del producto: leche, jamón, huevos, cacahuates, etc.
- Escriba un programa que modele e implemente la estructura de datos planteada por el diagrama de la estructura de datos.
- Sería sumamente conveniente y recomendable para el lector que, como parte de su diseño, realizara también el diagrama de clases UML de su propuesta de solución.
![]() |
| Abstracción de una estructura de datos compuesta. |
31 de marzo de 2017
Pilas (definición y operaciones primitivas).
Definición.
La pila es un objeto dinámico en constante cambio.
Una pila es un conjunto ordenado de elementos en el cual se pueden insertar y eliminar elementos únicamente por un extremo: el tope de la pila.
La característica más importante de una pila es que el último elemento insertado en ella es el primero en eliminarse, mientras que el primero que fue insertado es el último en eliminarse. Por esta razón se dice que una pila es una estructura de datos de tipo LIFO (Last In First Out).
El proceso de inserción y eliminación de elementos puede observarse en la siguiente figura en donde se muestra, por medio de una flecha, la representación del tope de la pila. Observe cómo con cada inserción o eliminación se modifica el tope de la pila.
Una pila es un conjunto ordenado de elementos en el cual se pueden insertar y eliminar elementos únicamente por un extremo: el tope de la pila.
La característica más importante de una pila es que el último elemento insertado en ella es el primero en eliminarse, mientras que el primero que fue insertado es el último en eliminarse. Por esta razón se dice que una pila es una estructura de datos de tipo LIFO (Last In First Out).
El proceso de inserción y eliminación de elementos puede observarse en la siguiente figura en donde se muestra, por medio de una flecha, la representación del tope de la pila. Observe cómo con cada inserción o eliminación se modifica el tope de la pila.
La representación mostrada en la figura anterior permite visualizar todos los elementos de la pila, sin embargo, es importante señalar que en un momento dado únicamente se tiene acceso al elemento que está siendo referido por el tope de la pila, los demás elementos permanecen ocultos, tapados por decirlo de alguna manera, por el conjunto de elementos que se encuentran encima de cada uno de ellos, con excepción del que está en el tope de la pila.
Operaciones primitivas.
Las operaciones primitivas o fundamentales definidas sobre una pila son la inserción (push) y la eliminación (pop).
Operaciones primitivas.
Las operaciones primitivas o fundamentales definidas sobre una pila son la inserción (push) y la eliminación (pop).
- El comportamiento definido para la operación push consiste en insertar un nuevo elemento en la pila, mismo que constituirá el nuevo tope de la pila.
- El comportamiento definido para la operación pop elimina el elemento referido por el tope de la pila modificando en consecuencia el tope de la pila. El nuevo tope de la pila se refiere ahora al elemento (si existe) que fue insertado inmediatamente antes que el elemento eliminado.
Existen otras operaciones útiles al usar pilas, como por ejemplo, antes de aplicar la operación pop a una pila, sería conveniente verificar que la pila no esté vacía (operación ¿Está vacía?).
Otro comportamiento deseable sería la operación "ojeada" (peek), la cual hecha un vistazo al elemento que se encuentra en el tope de la pila y lo regresa pero no lo elimina.
Las operaciones push, pop y peek, son muy comunes para la estructura de datos pila, por lo que se recomienda conservar dichos nombres en la implementación.
Otro comportamiento deseable sería la operación "ojeada" (peek), la cual hecha un vistazo al elemento que se encuentra en el tope de la pila y lo regresa pero no lo elimina.
Las operaciones push, pop y peek, son muy comunes para la estructura de datos pila, por lo que se recomienda conservar dichos nombres en la implementación.
14 de febrero de 2017
POO (mensajes y métodos).
Una de las principales inquietudes que expresan los estudiantes acerca del paradigma orientado a objetos está relacionada con los mensajes y los métodos. En este sentido, se iniciará con un ejemplo sumamente sencillo el cual irá evolucionando progresivamente con la finalidad de ilustrar dichos conceptos.
Métodos sin argumentos.
El Ejemplo Parvulo1 muestra la definición de la clase Parvulo1, misma que no contiene atributos pero sí un método cuyo identificador o nombre es mensaje.
El método mensaje tiene como única responsabilidad la impresión en la salida estándar de una cadena (los detalles generales del funcionamiento de println son presentados en la entrada Un vistazo al lenguaje Java).
En base a lo anterior, la clase Parvulo1 es una especie de plantilla capaz de generar objetos con una única responsabilidad o servicio, y no puede ser instanciada ni ejecutada por sí misma. Para poder instanciar objetos de la clase Parvulo1 y poder visualizar su funcionamiento, se requiere de una clase de prueba que permita generar una instancia de ella.
La clase de prueba para el Ejemplo Parvulo1 es la clase PruebaParvulo1 que se presenta en el Ejemplo PruebaParvulo1.
La clase PruebaParvulo1 tiene la estructura de la mayoría de las clases de prueba que se utilizarán en el blog, y está basada en la definición del método main.
En la línea 7 se define el objeto parvulo cuya clase (tipo) de la que deriva es Parvulo1; así mismo, observe que se genera una instancia por medio de la cláusula new, misma que, entre otras cosas, construye el objeto. Si la clase Parvulo1 tuviera un constructor explícito, sería precisamente aquí en donde se invocaría. Más adelante en esta misma entrada, se profundizará un poco más al respecto.
Una vez que el objeto existe, es decir, una vez que el objeto ha sido instanciado, es posible entonces interactuar con él por medio de mensajes para solicitarle acciones que correspondan con las responsabilidades o servicios definidos para dicho objeto que, para el caso del objeto parvulo, es sólo una.
La solicitud del único servicio que puede proporcionar el objeto parvulo se realiza a través del mensaje mensaje, el cual es enviado (invocado) al objeto en la línea 9:
Métodos sin argumentos.
El Ejemplo Parvulo1 muestra la definición de la clase Parvulo1, misma que no contiene atributos pero sí un método cuyo identificador o nombre es mensaje.
El método mensaje tiene como única responsabilidad la impresión en la salida estándar de una cadena (los detalles generales del funcionamiento de println son presentados en la entrada Un vistazo al lenguaje Java).
En base a lo anterior, la clase Parvulo1 es una especie de plantilla capaz de generar objetos con una única responsabilidad o servicio, y no puede ser instanciada ni ejecutada por sí misma. Para poder instanciar objetos de la clase Parvulo1 y poder visualizar su funcionamiento, se requiere de una clase de prueba que permita generar una instancia de ella.
La clase de prueba para el Ejemplo Parvulo1 es la clase PruebaParvulo1 que se presenta en el Ejemplo PruebaParvulo1.
La clase PruebaParvulo1 tiene la estructura de la mayoría de las clases de prueba que se utilizarán en el blog, y está basada en la definición del método main.
En la línea 7 se define el objeto parvulo cuya clase (tipo) de la que deriva es Parvulo1; así mismo, observe que se genera una instancia por medio de la cláusula new, misma que, entre otras cosas, construye el objeto. Si la clase Parvulo1 tuviera un constructor explícito, sería precisamente aquí en donde se invocaría. Más adelante en esta misma entrada, se profundizará un poco más al respecto.
Una vez que el objeto existe, es decir, una vez que el objeto ha sido instanciado, es posible entonces interactuar con él por medio de mensajes para solicitarle acciones que correspondan con las responsabilidades o servicios definidos para dicho objeto que, para el caso del objeto parvulo, es sólo una.
La solicitud del único servicio que puede proporcionar el objeto parvulo se realiza a través del mensaje mensaje, el cual es enviado (invocado) al objeto en la línea 9:
parvulo.mensaje();
La expresión anterior se interpreta como: "se envía el mensaje mensaje al objeto parvulo". El envío de mensajes no es otra cosa más que la invocación explícita de un método a través de su identificador, es utilizar el método correspondiente para realizar una acción, misma que está relacionada con el comportamiento o las responsabilidades del objeto en cuestión.
La salida del Ejemplo PruebaParvulo1 se muestra en la siguiente figura. Asegúrese de comprender lo descrito hasta aquí antes de continuar.
La salida del Ejemplo PruebaParvulo1 se muestra en la siguiente figura. Asegúrese de comprender lo descrito hasta aquí antes de continuar.
Métodos con argumentos.
En esta sección se presenta una versión ligeramente distinta del Ejemplo Parvulo1, en el cual se presentó el envío de mensajes sin argumentos. Tómese el tiempo necesario para comparar el Ejemplo Parvulo2 de esta sección con el Ejemplo Parvulo1 de la sección anterior, y compruebe que son esencialmente iguales.
El parámetro nombre en el método mensaje constituye la diferencia de los ejemplos anteriormente mencionados. En el Ejemplo Parvulo2 el método mensaje (línea 5) define ahora la capacidad de recibir un argumento de tipo cadena (un objeto de la clase String) referido por el objeto nombre. El método mensaje imprime en la salida estándar un cadena conformada por un texto predefinido (línea 6) y la cadena referida por nombre.
Por otro lado, el Ejemplo PruebaParvulo2 muestra la clase de prueba para el Ejemplo Parvulo2, la cual es también similar a la del Ejemplo PruebaParvulo1 excepto en la forma en que se envía el mensaje al objeto parvulo (línea 10 del Ejemplo PruebaParvulo2). Observe que el mensaje enviado tiene ahora una cadena como argumento, la cual es referida por el objeto nombre del método mensaje (línea 5 del Ejemplo Parvulo2) en el momento en que se le envía el mensaje mensaje al objeto parvulo.
Asegúrese de realizar una labor analítica al comparar línea a línea tanto las clases Parvulo1 y Parvulo2, como las clases PruebaParvulo1 y PruebaParvulo2 así como de comprender sus diferencias en base a lo que se ha descrito hasta ahora.
La salida del Ejemplo PruebaParvulo2 se muestra en la siguiente figura:
En esta sección se presenta una versión ligeramente distinta del Ejemplo Parvulo1, en el cual se presentó el envío de mensajes sin argumentos. Tómese el tiempo necesario para comparar el Ejemplo Parvulo2 de esta sección con el Ejemplo Parvulo1 de la sección anterior, y compruebe que son esencialmente iguales.
El parámetro nombre en el método mensaje constituye la diferencia de los ejemplos anteriormente mencionados. En el Ejemplo Parvulo2 el método mensaje (línea 5) define ahora la capacidad de recibir un argumento de tipo cadena (un objeto de la clase String) referido por el objeto nombre. El método mensaje imprime en la salida estándar un cadena conformada por un texto predefinido (línea 6) y la cadena referida por nombre.
Por otro lado, el Ejemplo PruebaParvulo2 muestra la clase de prueba para el Ejemplo Parvulo2, la cual es también similar a la del Ejemplo PruebaParvulo1 excepto en la forma en que se envía el mensaje al objeto parvulo (línea 10 del Ejemplo PruebaParvulo2). Observe que el mensaje enviado tiene ahora una cadena como argumento, la cual es referida por el objeto nombre del método mensaje (línea 5 del Ejemplo Parvulo2) en el momento en que se le envía el mensaje mensaje al objeto parvulo.
Asegúrese de realizar una labor analítica al comparar línea a línea tanto las clases Parvulo1 y Parvulo2, como las clases PruebaParvulo1 y PruebaParvulo2 así como de comprender sus diferencias en base a lo que se ha descrito hasta ahora.
La salida del Ejemplo PruebaParvulo2 se muestra en la siguiente figura:
![]() |
| Salida del Ejemplo PruebaParvulo2. |
Métodos y atributos.
Por el principio de ocultación de información es conveniente que únicamente se tenga acceso a los atributos de una clase a través de su interfaz. La interfaz de un objeto está representada por sus métodos públicos (public).
El Ejemplo Parvulo3 hace uso de dicho principio al definir, con un acceso restringido o privado (private), el atributo nombre (línea 6) para la clase Parvulo3. Observe que dicha clase define también tres métodos públicos, los cuales establecen la interfaz de los objetos que sean instanciados:
Por el principio de ocultación de información es conveniente que únicamente se tenga acceso a los atributos de una clase a través de su interfaz. La interfaz de un objeto está representada por sus métodos públicos (public).
El Ejemplo Parvulo3 hace uso de dicho principio al definir, con un acceso restringido o privado (private), el atributo nombre (línea 6) para la clase Parvulo3. Observe que dicha clase define también tres métodos públicos, los cuales establecen la interfaz de los objetos que sean instanciados:
- estableceNombre: este tipo de métodos son utilizados comúnmente para ajustar o establecer el valor de un atributo; y al menos en principio, debería haber un método de este tipo por cada atributo que contenga la clase y que se requiera manipular desde el exterior. Este tipo de métodos son comúnmente referidos como métodos de tipo set.
- obtenNombre: este tipo de métodos son utilizados comúnmente para recuperar u obtener el valor de un atributo, y al igual que antes, debería haber, al menos en principio, un método de este tipo por cada atributo que contenga la clase y que se requiera visualizar desde el exterior. Este tipo de métodos son comúnmente referidos como métodos de tipo get.
- mensaje: este ha sido descrito con anterioridad. Note que el método está definido como el del Ejemplo Parvulo1 (sin argumentos), pero funciona como el del Ejemplo Parvulo2. Asegúrese de comprender ésto antes de continuar.
Observe que el método mensaje (líneas 16-18) se vale del método obtenNombre (línea 17) para acceder al atributo nombre pero no necesariamente tiene que ser así, ya que un método puede acceder directamente a los atributos de la clase, siempre y cuando ambos estén definidos dentro de la misma clase (encapsulamiento). Por otro lado, si el atributo tiene un nivel de acceso protegido (protected), los métodos de las clases derivadas por herencia también podrían acceder a los atributos de la clase de la que derivan (clase padre o super clase).
Los métodos de tipo set sólo deben trabajar sobre un atributo, por lo que habitualmente sólo reciben un argumento, mismo que se corresponde con la clase (tipo) del atributo a modificar (String para el caso del Ejemplo Parvulo3). De manera análoga, los métodos de tipo get no reciben ningún tipo de argumento, y la clase de objetos que regresan está directamente relacionada con la clase del atributo al que accederán (String para el caso del Ejemplo Parvulo3).
Es importante hacer notar también que la clase Parvulo3, a diferencia de las anteriores, establece ya una característica representada y definida por el atributo nombre, de tal forma que los objetos derivados de ella (párvulos) compartirán dicha característica (un párvulo es un niño pequeño en edad preescolar), aunque cada uno poseerá su propia identidad (nombre).
El Ejemplo PruebaParvulo3 muestra la clase de prueba para la clase Parvulo3. Al igual que en los ejemplos anteriores para las clases de prueba, observe que en la línea 7 se define y crea el objeto parvulo.
Las líneas 9 y 11 hacen uso del método obtenNombre a través del envío del mensaje correspondiente, mientras que la línea 10 envía el mensaje estableceNombre con un argumento específico. Finalmente, la línea 12 muestra el envío del mensaje mensaje, el cual debería resultarle ya familiar al lector.
La salida del Ejemplo PruebaParvulo3 se muestra en la siguiente figura. Observe que inicialmente el atributo nombre del objeto parvulo no está definido, de ahí que se imprima null en la salida estándar, el cual es el valor por omisión en Java para las referencias a objetos que no han sido instanciados, es decir, cuando los objetos todavía no existen y por consiguiente no han sido inicializados.
Los métodos de tipo set sólo deben trabajar sobre un atributo, por lo que habitualmente sólo reciben un argumento, mismo que se corresponde con la clase (tipo) del atributo a modificar (String para el caso del Ejemplo Parvulo3). De manera análoga, los métodos de tipo get no reciben ningún tipo de argumento, y la clase de objetos que regresan está directamente relacionada con la clase del atributo al que accederán (String para el caso del Ejemplo Parvulo3).
Es importante hacer notar también que la clase Parvulo3, a diferencia de las anteriores, establece ya una característica representada y definida por el atributo nombre, de tal forma que los objetos derivados de ella (párvulos) compartirán dicha característica (un párvulo es un niño pequeño en edad preescolar), aunque cada uno poseerá su propia identidad (nombre).
El Ejemplo PruebaParvulo3 muestra la clase de prueba para la clase Parvulo3. Al igual que en los ejemplos anteriores para las clases de prueba, observe que en la línea 7 se define y crea el objeto parvulo.
Las líneas 9 y 11 hacen uso del método obtenNombre a través del envío del mensaje correspondiente, mientras que la línea 10 envía el mensaje estableceNombre con un argumento específico. Finalmente, la línea 12 muestra el envío del mensaje mensaje, el cual debería resultarle ya familiar al lector.
La salida del Ejemplo PruebaParvulo3 se muestra en la siguiente figura. Observe que inicialmente el atributo nombre del objeto parvulo no está definido, de ahí que se imprima null en la salida estándar, el cual es el valor por omisión en Java para las referencias a objetos que no han sido instanciados, es decir, cuando los objetos todavía no existen y por consiguiente no han sido inicializados.
![]() |
| Salida del Ejemplo PruebaParvulo3. |
Métodos y constructores.
Un constructor es un método especial que se invoca implícitamente cuando se crea o instancia un objeto por medio de la cláusula new.
La cláusula new genera la memoria necesaria para representar al objeto correspondiente y lo inicializa por medio de un constructor. En este sentido, puede haber más de una forma de inicializar un objeto y, en consecuencia, más de un constructor.
El identificador o nombre de los métodos constructores debe coincidir con el identificador o nombre de la clase que los define; en base a lo anterior se tiene que puede haber más de un constructor compartiendo el mismo identificador. El mecanismo que tienen los constructores para distinguirse entre sí, es a través del número y clase o tipo de los parámetros que definen, constituyendo con ello una forma de polimorfismo comúnmente conocida como sobrecarga (la sobrecarga se trata con un poco más de detalle en la siguiente sección). En la creación del objeto, se invoca el constructor que coincida con el número y tipo de argumentos proporcionados a la cláusula new.
Las líneas 9-11 del Ejemplo Parvulo4 muestran la definición del constructor Parvulo4, observe cómo el nombre del constructor coincide exactamente con el nombre de la clase. Dicho constructor define un único parámetro n el cual es un objeto de la clase String.
La inicialización que hace el constructor Parvulo4 consiste únicamente de la asignación del objeto n al atributo representado por el objeto nombre.
Es importante mencionar que la labor de inicialización de un constructor en particular puede ser un proceso mucho más elaborado que el descrito hasta ahora, y que estará en función directa de las responsabilidades de inicialización con que se quiera dotar al constructor y de la problemática en particular que se esté resolviendo por medio del objeto en cuestión.
Los elementos restantes de la clase Parvulo4 han sido previamente abordados en las secciones anteriores por lo que no se repetirán aquí.
El Ejemplo PruebaParvulo4 presenta la clase de prueba para el Ejemplo Parvulo4. Observe que a diferencia de los ejemplos anteriores, en la línea 8 se proporciona un argumento al constructor Parvulo4, lo cual hace que desde la creación del objeto parvulo se le esté definiendo un nombre.
Observe también cómo la secuencia de mensajes subsecuentes coincide con las del Ejemplo PruebaParvulo3, excepto que en la línea 11 del Ejemplo PruebaParvulo4, se envía el mensaje estableceNombre al objeto parvulo para asignarle el nombre completo (con apellidos) al párvulo.
Asegúrese de comprender antes de continuar, que la siguiente figura muestra la salida correspondiente a la ejecución del Ejemplo PruebaParvulo4:
Un constructor es un método especial que se invoca implícitamente cuando se crea o instancia un objeto por medio de la cláusula new.
La cláusula new genera la memoria necesaria para representar al objeto correspondiente y lo inicializa por medio de un constructor. En este sentido, puede haber más de una forma de inicializar un objeto y, en consecuencia, más de un constructor.
El identificador o nombre de los métodos constructores debe coincidir con el identificador o nombre de la clase que los define; en base a lo anterior se tiene que puede haber más de un constructor compartiendo el mismo identificador. El mecanismo que tienen los constructores para distinguirse entre sí, es a través del número y clase o tipo de los parámetros que definen, constituyendo con ello una forma de polimorfismo comúnmente conocida como sobrecarga (la sobrecarga se trata con un poco más de detalle en la siguiente sección). En la creación del objeto, se invoca el constructor que coincida con el número y tipo de argumentos proporcionados a la cláusula new.
Las líneas 9-11 del Ejemplo Parvulo4 muestran la definición del constructor Parvulo4, observe cómo el nombre del constructor coincide exactamente con el nombre de la clase. Dicho constructor define un único parámetro n el cual es un objeto de la clase String.
La inicialización que hace el constructor Parvulo4 consiste únicamente de la asignación del objeto n al atributo representado por el objeto nombre.
Es importante mencionar que la labor de inicialización de un constructor en particular puede ser un proceso mucho más elaborado que el descrito hasta ahora, y que estará en función directa de las responsabilidades de inicialización con que se quiera dotar al constructor y de la problemática en particular que se esté resolviendo por medio del objeto en cuestión.
Los elementos restantes de la clase Parvulo4 han sido previamente abordados en las secciones anteriores por lo que no se repetirán aquí.
El Ejemplo PruebaParvulo4 presenta la clase de prueba para el Ejemplo Parvulo4. Observe que a diferencia de los ejemplos anteriores, en la línea 8 se proporciona un argumento al constructor Parvulo4, lo cual hace que desde la creación del objeto parvulo se le esté definiendo un nombre.
Observe también cómo la secuencia de mensajes subsecuentes coincide con las del Ejemplo PruebaParvulo3, excepto que en la línea 11 del Ejemplo PruebaParvulo4, se envía el mensaje estableceNombre al objeto parvulo para asignarle el nombre completo (con apellidos) al párvulo.
Asegúrese de comprender antes de continuar, que la siguiente figura muestra la salida correspondiente a la ejecución del Ejemplo PruebaParvulo4:
| Salida del Ejemplo PruebaParvulo4. |
Sobrecarga.
La sobrecarga (overload) es un tipo de polimorfismo que se caracteriza por la capacidad de poder definir más de un método o constructor con el mismo nombre (identificador), siendo distinguidos entre sí por el número y la clase (tipo) de los argumentos que se definen.
El Ejemplo Parvulo5 muestra la sobrecarga de constructores. Note que las líneas 8-10 definen el mismo constructor que el del Ejemplo Parvulo4 excepto por el nombre, y que se ha añadido o sobrecargado un nuevo constructor (líneas 12-14), el cual recibe tres argumentos que representan el nombre (n), el primer apellido (a1), y el segundo apellido (a2) de un párvulo.
La sobrecarga de constructores se da porque ambos constructores tiene el mismo identificador (Parvulo5) pero distinto número de parámetros.
No puede existir sobrecarga para constructores o métodos con el mismo identificador y el mismo número o clase (tipo) de parámetros; tiene que haber algo que los distinga entre sí, ya que en otro caso habría ambigüedad.
Los métodos restantes del Ejemplo Parvulo5 ya ha sido comentados con anterioridad en otras secciones de esta misma entrada.
La clase de prueba para el Ejemplo Parvulo5 se muestra en el Ejemplo PruebaParvulo5, la cual es también muy similar a las clases de prueba anteriormente explicadas. Únicamente cabe resaltar la creación del objeto parvulo en la línea 7. Note que ahora se le proporcionan tres argumentos al constructor, lo cual hace que el constructor utilizado sea el definido en las líneas 12-14 del Ejemplo Parvulo5.
La salida del Ejemplo PruebaParvulo5 aparece en la siguiente figura. Compare dicha salida con la de la figura anterior y asegúrese de comprender la diferencia.
La sobrecarga (overload) es un tipo de polimorfismo que se caracteriza por la capacidad de poder definir más de un método o constructor con el mismo nombre (identificador), siendo distinguidos entre sí por el número y la clase (tipo) de los argumentos que se definen.
El Ejemplo Parvulo5 muestra la sobrecarga de constructores. Note que las líneas 8-10 definen el mismo constructor que el del Ejemplo Parvulo4 excepto por el nombre, y que se ha añadido o sobrecargado un nuevo constructor (líneas 12-14), el cual recibe tres argumentos que representan el nombre (n), el primer apellido (a1), y el segundo apellido (a2) de un párvulo.
La sobrecarga de constructores se da porque ambos constructores tiene el mismo identificador (Parvulo5) pero distinto número de parámetros.
No puede existir sobrecarga para constructores o métodos con el mismo identificador y el mismo número o clase (tipo) de parámetros; tiene que haber algo que los distinga entre sí, ya que en otro caso habría ambigüedad.
Los métodos restantes del Ejemplo Parvulo5 ya ha sido comentados con anterioridad en otras secciones de esta misma entrada.
La clase de prueba para el Ejemplo Parvulo5 se muestra en el Ejemplo PruebaParvulo5, la cual es también muy similar a las clases de prueba anteriormente explicadas. Únicamente cabe resaltar la creación del objeto parvulo en la línea 7. Note que ahora se le proporcionan tres argumentos al constructor, lo cual hace que el constructor utilizado sea el definido en las líneas 12-14 del Ejemplo Parvulo5.
La salida del Ejemplo PruebaParvulo5 aparece en la siguiente figura. Compare dicha salida con la de la figura anterior y asegúrese de comprender la diferencia.
Etiquetas:
Atributo,
Clase,
Comportamiento,
Constructor,
Encapsulamiento,
Herencia,
Information hiding,
Instancia,
Interfaz,
main,
Métodos,
new,
Nivel de acceso,
overload,
Polimorfismo,
POO,
println,
Servicios
7 de febrero de 2017
Orientación a Objetos (conceptos).
Objetos.
Los objetos son esencialmente abstracciones. Son entidades que tienen un determinado estado, un comportamiento (determinado por sus responsabilidades), y una identidad.
Los objetos son esencialmente abstracciones. Son entidades que tienen un determinado estado, un comportamiento (determinado por sus responsabilidades), y una identidad.
- El estado está representado por los datos o los valores que contienen los atributos del objeto, los cuales son a su vez otros objetos o variables que representan las características inherentes del objeto.
- El comportamiento está determinado por las responsabilidades o servicios del objeto los cuales son definidos por los métodos, mismos que se solicitan a través de mensajes a los que dicho objeto sabe responder.
- La identidad es la propiedad que tiene un objeto que lo distingue o hace diferente de los demás. La identidad está representada por un identificador.
Un objeto es una entidad que contiene en sí mismo, al menos en principio, toda la información necesaria que permite definirlo, identificarlo, y accederlo respecto a otros objetos pertenecientes a otras clases, e incluso respecto a objetos de su misma clase. La forma de acceder a un objeto es a través de su interfaz. La interfaz de un objeto es el conjunto de servicios públicos que ofrece el objeto, mismos que se solicitan a través de mensajes o solicitudes realizadas a dicho objeto.
Los objetos se valen de mecanismos de interacción llamados métodos que favorecen la comunicación entre ellos. Dicha comunicación favorece a su vez el cambio de estado en los propios objetos. Esta característica define a los objetos como unidades indivisibles en las que no se separa el estado del comportamiento.
Orientación a objetos vs. enfoque estructurado.
La orientación a objetos difiere del enfoque estructurado básicamente en que en la programación estructurada los datos y los procedimientos están separados y sin relación explícita, ya que lo único que se busca en la programación estructurada es el procesamiento de los datos de entrada para obtener los datos de salida.
La programación estructurada utiliza en primera instancia un enfoque basado en procedimientos o funciones, y en segunda instancia, las estructuras de datos que dichos procedimientos o funciones manejan, cumpliendo así con la ecuación planteada por Niklaus Wirth:
Los objetos se valen de mecanismos de interacción llamados métodos que favorecen la comunicación entre ellos. Dicha comunicación favorece a su vez el cambio de estado en los propios objetos. Esta característica define a los objetos como unidades indivisibles en las que no se separa el estado del comportamiento.
Orientación a objetos vs. enfoque estructurado.
La orientación a objetos difiere del enfoque estructurado básicamente en que en la programación estructurada los datos y los procedimientos están separados y sin relación explícita, ya que lo único que se busca en la programación estructurada es el procesamiento de los datos de entrada para obtener los datos de salida.
La programación estructurada utiliza en primera instancia un enfoque basado en procedimientos o funciones, y en segunda instancia, las estructuras de datos que dichos procedimientos o funciones manejan, cumpliendo así con la ecuación planteada por Niklaus Wirth:
Algoritmos + Estructuras de Datos = Programas
Por otro lado, un programa en un enfoque OO solicita estructuras de datos (las cuales son otros objetos) para llevar a cabo un servicio.
La perspectiva OO también define programas compuestos por algoritmos y estructuras de datos esencialmente; sin embargo, lo hace desde un enfoque diferente. En la orientación a objetos la descripción del objeto se da en términos de responsabilidades y características; y así, al analizar un problema en dichos términos, se eleva el nivel de abstracción.
Lo anterior permite una mayor independencia entre los objetos, lo cual es un factor crítico en la solución de problemas complejos. Cabe mencionar por último en este sentido, que al conjunto completo de responsabilidades asociadas a un objeto se le refiere comúnmente como protocolo.
Objetos y clases.
Todos los objetos son instancias de una clase (categoría). Esta relación de un objeto con una clase, hace que los objetos tengan las siguientes características:
La perspectiva OO también define programas compuestos por algoritmos y estructuras de datos esencialmente; sin embargo, lo hace desde un enfoque diferente. En la orientación a objetos la descripción del objeto se da en términos de responsabilidades y características; y así, al analizar un problema en dichos términos, se eleva el nivel de abstracción.
Lo anterior permite una mayor independencia entre los objetos, lo cual es un factor crítico en la solución de problemas complejos. Cabe mencionar por último en este sentido, que al conjunto completo de responsabilidades asociadas a un objeto se le refiere comúnmente como protocolo.
Objetos y clases.
Todos los objetos son instancias de una clase (categoría). Esta relación de un objeto con una clase, hace que los objetos tengan las siguientes características:
- El método invocado por un objeto en respuesta a un mensaje es determinado por la clase del objeto receptor.
- Todos los objetos de una clase determinada utilizan el mismo método en respuesta a mensajes similares.
- Las clases pueden ser organizadas en una estructura jerárquica de herencia como la que se muestra en la figura de abajo.
- Una clase hija o subclase heredará todas las características de la clase de la que deriva (clase padre clase madre o súper clase).
- Una clase abstracta es una clase de la que no se derivan instancias directamente, sino que es utilizada únicamente para crear subclases.
- La búsqueda del método a invocar en respuesta a un mensaje determinado inicia en la clase del receptor. Si no se encuentra el método apropiado, la búsqueda se realiza en la clase padre, si no se encuentra ahí, se busca en la clase padre de la clase padre y así sucesivamente hasta encontrar el método correspondiente.
- Si se encuentran métodos con el mismo nombre dentro de la jerarquía de clases, se dice que el método procesado sobre escribe (override) el comportamiento heredado.
![]() |
| Diagrama de ejemplo de jerarquía de clases. |
La figura anterior presenta una posible jerarquía de clases para un Ser Vivo. Más que una clasificación o taxonomía completa, la figura muestra el concepto de herencia a través de un árbol. En la figura puede observarse que los elementos que se derivan comparten características (atributos) y comportamientos (métodos) semejantes.
Así por ejemplo, es posible decir que Flipper es una instancia particular de todos los posibles delfines que podrían existir. A su vez, un Delfín comparte características comunes con una Ballena en cuanto a que ambos son Cetáceos pero difieren en otras (si un delfín y una ballena coincidieran en todo (características y comportamiento) serían de la misma clase).
Un Delfín es un Cetáceo, y un Cetáceo es un Mamífero. En muchas ocasiones a éste tipo de relaciones se le denomina "es un" (is a), y es una característica útil para identificar herencia pero no es la única.
Existe otro tipo de relación y se denomina "tiene" (has-a). Estas relaciones son dos formas importantes de abstracción en la orientación a objetos:
Así por ejemplo, es posible decir que Flipper es una instancia particular de todos los posibles delfines que podrían existir. A su vez, un Delfín comparte características comunes con una Ballena en cuanto a que ambos son Cetáceos pero difieren en otras (si un delfín y una ballena coincidieran en todo (características y comportamiento) serían de la misma clase).
Un Delfín es un Cetáceo, y un Cetáceo es un Mamífero. En muchas ocasiones a éste tipo de relaciones se le denomina "es un" (is a), y es una característica útil para identificar herencia pero no es la única.
Existe otro tipo de relación y se denomina "tiene" (has-a). Estas relaciones son dos formas importantes de abstracción en la orientación a objetos:
- La idea de división en partes (has-a): un automóvil tiene un motor, tiene una transmisión, tiene un sistema eléctrico, etc.
- La idea de división en especializaciones (is-a): un automóvil es un medio de transporte, es un objeto de cuatro ruedas, es un objeto que se dirige con un volante, etc.
Etiquetas:
Abstracción,
Atributo,
Clase,
Clase abstracta,
Comportamiento,
Enfoque estructurado,
Entidad,
Herencia,
Instancia,
Interfaz,
Métodos,
Niklaus Wirth,
OO,
override,
POO,
Programación
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]:
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:
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:
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:
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:
- Entidades: agentes u objetos en interacción, donde cada uno de ellos tiene un rol y características denotadas por atributos.
- 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.
- 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:
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:
- En un mensaje hay un receptor designado para dicho mensaje. Las funciones o procedimientos son generales, no hay un receptor específico.
- 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.
Suscribirse a:
Entradas (Atom)



















