Simulador EGEL Ingeniería de Software

🔀 Paradigmas de programación

Paradigmas de programación

Un paradigma es un modelo de cómo estructurar la computación. El paradigma imperativo describe el cómputo como una secuencia de sentencias que cambian el estado del programa mediante asignaciones; el orden de ejecución es significativo y se apoya en estructuras de control: secuencia, selección e iteración (estilo estructurado). En oposición, el paradigma declarativo especifica QUÉ resultado se desea sin describir el flujo de control paso a paso, y engloba los subparadigmas funcional y lógico.

La programación orientada a objetos (POO) organiza el software en objetos que combinan estado (atributos) y comportamiento (métodos). Sus cuatro pilares son:

El paradigma funcional modela el cómputo como la evaluación de funciones matemáticas; su fundamento teórico es el cálculo lambda (A. Church, 1936). Evita el estado mutable y los efectos secundarios, y favorece la composición. Una función pura produce siempre la misma salida para las mismas entradas y no genera efectos secundarios observables. De ello deriva la transparencia referencial: una expresión puede sustituirse por su valor sin alterar el programa. Las funciones son de primera clase (se asignan, pasan y retornan) y las de orden superior reciben o devuelven otras funciones. La inmutabilidad implica que las 'actualizaciones' generan nuevos valores en vez de mutar los existentes. El paradigma lógico expresa hechos y reglas para que el motor infiera respuestas, y el concurrente coordina tareas simultáneas.

Para trazar código dado en texto: un bucle for/while con variable acumuladora y asignaciones es imperativo; operaciones map, filter y reduce sobre una colección expresan lo mismo en estilo funcional sin mutar estado. En POO se sigue el envío de mensajes (llamadas a métodos) resolviendo el método concreto según la clase del receptor (despacho dinámico). Conviene recordar las estructuras de datos (arreglos, apuntadores, estructuras dinámicas, cadenas) y las operaciones/recorridos de pilas (LIFO), colas (FIFO), árboles y grafos. Existen lenguajes multiparadigma como Python, C++, JavaScript y Scala.

Practica el banco completo y haz simulacros gratis

Preguntas de muestra (35)

1. ¿Qué característica define fundamentalmente al paradigma de programación imperativo?

  1. Describe la computación como una secuencia de sentencias que modifican el estado del programa mediante asignaciones, donde el orden de ejecución es significativo.
  2. Especifica el resultado deseado mediante relaciones lógicas entre hechos, sin describir el flujo de control paso a paso.
  3. Modela la computación como la evaluación de funciones matemáticas, evitando el estado mutable y los efectos secundarios.
  4. Organiza el software en unidades que combinan estado interno y comportamiento, comunicándose mediante el envío de mensajes.

El paradigma imperativo se define por sentencias que cambian el estado del programa mediante asignaciones y por la importancia del orden de ejecución; las demás opciones describen los paradigmas lógico, funcional y orientado a objetos. (Robert W. Sebesta, Concepts of Programming Languages, cap. 1 (clasificación de paradigmas))

2. ¿Cuáles son las tres estructuras de control fundamentales de la programación estructurada?

  1. Herencia, encapsulamiento y polimorfismo.
  2. Secuencia, selección e iteración.
  3. Recursión, composición y aplicación parcial.
  4. Exclusión mutua, sincronización y bloqueo.

La programación estructurada se basa en secuencia, selección e iteración como estructuras de control básicas; las demás opciones corresponden a la POO, la programación funcional y la concurrencia. (Sebesta, Concepts of Programming Languages, cap. 1)

3. Un desarrollador calcula el promedio de un arreglo de números usando un ciclo for que en cada iteración acumula la suma en una variable y, al terminar el ciclo, divide dicha variable entre el número de elementos. ¿A qué paradigma corresponde este enfoque de solución?

  1. Lógico, porque el resultado se obtiene mediante hechos y reglas sobre los elementos del arreglo.
  2. Funcional puro, porque el ciclo evita modificar cualquier variable durante su ejecución.
  3. Imperativo, porque usa un ciclo con una variable acumuladora que cambia de estado en cada iteración.
  4. Orientado a objetos, porque el arreglo se trata como una instancia con métodos propios.

El uso de un ciclo con una variable acumuladora que se reasigna en cada paso es característico del estilo imperativo, no del funcional (que evita mutar estado) ni del lógico u orientado a objetos. (Sebesta, Concepts of Programming Languages, cap. 1)

4. Desde la perspectiva de la programación funcional, ¿cuál de las siguientes acciones realizadas dentro de una función constituye un efecto secundario (side effect)?

  1. Retornar un valor calculado a partir de los parámetros recibidos.
  2. Declarar una variable local que solo existe durante la ejecución de la función.
  3. Comparar dos parámetros de entrada para decidir cuál es mayor.
  4. Modificar el valor de una variable global desde dentro de la función.

Un efecto secundario implica modificar estado observable fuera del ámbito local, como una variable global; las demás acciones no alteran estado externo a la función. (Sebesta, Concepts of Programming Languages (side effects y sentencia de asignación))

5. Según el teorema de la programación estructurada (Böhm-Jacopini), ¿qué conjunto mínimo de estructuras de control basta para expresar cualquier programa que calcule una función computable?

  1. Secuencia, selección e iteración.
  2. Secuencia, selección y la instrucción goto.
  3. Selección, iteración y concurrencia de procesos.
  4. Secuencia, recursión y mensajes entre objetos.

El teorema de Böhm-Jacopini (1966) demuestra que secuencia, selección e iteración son suficientes para expresar cualquier función computable, eliminando la necesidad del goto. (C. Böhm y G. Jacopini, 'Flow diagrams, turing machines and languages with only two formation rules', Communications of the ACM, 1966)

6. ¿Qué crítica formuló Edsger Dijkstra en 1968 contra el uso indiscriminado de la instrucción goto en programas imperativos?

  1. Que impide declarar variables locales dentro de los procedimientos.
  2. Que dificulta seguir el flujo de control del programa y produce código difícil de mantener.
  3. Que obliga a sustituir todas las iteraciones por llamadas recursivas.
  4. Que impide compilar el programa en lenguajes de alto nivel.

En su carta 'Go To Statement Considered Harmful', Dijkstra argumentó que el goto oscurece el flujo de control y dificulta la verificación y el mantenimiento del código. (E. W. Dijkstra, 'Go To Statement Considered Harmful', Communications of the ACM, 1968)

7. Un ingeniero de software debe programar una rutina que lea el estado de varios sensores en un orden específico, verifique condiciones sobre cada lectura y actualice registros de memoria paso a paso conforme avanza. ¿Qué paradigma resulta más directo para expresar esta lógica?

  1. Funcional puro, porque la solución evita cualquier modificación de estado durante la lectura de los sensores.
  2. Lógico, porque la solución se expresa como hechos y reglas sobre las lecturas de los sensores.
  3. Imperativo estructurado, porque la solución depende de una secuencia ordenada de pasos que modifican el estado del sistema.
  4. Concurrente basado en actores, porque cada sensor debe ejecutarse en un proceso independiente.

Una secuencia ordenada de lecturas, verificaciones y actualizaciones de estado paso a paso es el escenario natural del paradigma imperativo estructurado; los otros paradigmas no capturan directamente la dependencia del orden ni el cambio de estado explícito. (Sebesta, Concepts of Programming Languages, cap. 1)

8. ¿Cuál de las siguientes NO se considera una estructura de control fundamental de la programación estructurada?

  1. La secuencia de sentencias ejecutadas una tras otra.
  2. La selección mediante condicionales (si-entonces-sino).
  3. La iteración mediante ciclos (mientras, para).
  4. El salto incondicional (goto) hacia cualquier punto del programa.

La programación estructurada excluye deliberadamente el goto, sustituyéndolo por secuencia, selección e iteración como estructuras fundamentales. (Böhm y Jacopini, CACM, 1966; Dijkstra, CACM, 1968)

9. Dentro del paradigma imperativo, ¿cuál es la función principal de una sentencia de asignación?

  1. Cambiar el valor almacenado en una variable, alterando el estado del programa.
  2. Declarar el tipo de dato de una variable sin asociarle ningún valor.
  3. Definir la interfaz pública que expone un módulo a otros módulos.
  4. Establecer una relación de herencia entre dos clases del programa.

La sentencia de asignación es el mecanismo central del paradigma imperativo para cambiar el estado del programa; las otras opciones corresponden a declaración de tipos, modularidad y herencia en POO. (Sebesta, Concepts of Programming Languages, cap. 1)

10. ¿Cómo se representa el conocimiento de un problema en el paradigma de programación lógica, como el implementado en Prolog?

  1. Mediante secuencias de instrucciones que modifican variables paso a paso.
  2. Mediante hechos y reglas expresados como cláusulas lógicas.
  3. Mediante objetos que encapsulan estado y comportamiento.
  4. Mediante funciones puras que se componen entre sí.

En el paradigma lógico, el conocimiento se declara como hechos y reglas (cláusulas), y el motor de inferencia deriva las respuestas; las demás opciones describen los paradigmas imperativo, orientado a objetos y funcional. (Sebesta, Concepts of Programming Languages, cap. 16 (Logic Programming Languages))

11. ¿Qué mecanismo emplea el motor de inferencia de un lenguaje lógico como Prolog para determinar si una consulta (meta) se satisface a partir de los hechos y reglas disponibles?

  1. Recolección de basura generacional sobre el montículo (heap).
  2. Despacho dinámico de métodos según la clase del objeto receptor.
  3. Unificación y resolución con retroceso (backtracking).
  4. Paso de mensajes asíncrono entre procesos independientes.

El motor lógico intenta unificar la meta con hechos o cabezas de reglas y, si falla, retrocede (backtracking) para probar otra alternativa; las demás opciones pertenecen a la gestión de memoria, la POO y la concurrencia. (Sebesta, Concepts of Programming Languages, cap. 16)

12. En el paradigma lógico, ¿qué nombre recibe el proceso mediante el cual el motor de inferencia deshace una decisión previa y explora una alternativa distinta cuando una rama de búsqueda falla?

  1. Recursión de cola (tail recursion).
  2. Herencia múltiple entre clases.
  3. Sincronización mediante semáforos.
  4. Backtracking (retroceso).

El backtracking es el mecanismo que permite al motor lógico retroceder y probar unificaciones alternativas cuando una rama de búsqueda no satisface la meta. (Sebesta, Concepts of Programming Languages, cap. 16)

13. ¿Cuál es la diferencia conceptual entre concurrencia y paralelismo en el diseño de programas?

  1. La concurrencia consiste en tareas cuya ejecución se traslapa en el tiempo, mientras que el paralelismo requiere ejecución simultánea real en varios procesadores.
  2. La concurrencia ocurre en un solo núcleo de procesamiento, mientras que el paralelismo ocurre en sistemas distribuidos con varias máquinas.
  3. Concurrencia y paralelismo son términos equivalentes que describen el mismo fenómeno de ejecución de programas en cualquier sistema.
  4. El paralelismo consiste en dividir un problema mediante recursión, sin relación con el hardware disponible para ejecutarlo.

La concurrencia se refiere a tareas cuya ejecución se traslapa lógicamente en el tiempo, mientras que el paralelismo exige ejecución simultánea real sobre múltiples unidades de procesamiento. (Sebesta, Concepts of Programming Languages, cap. 13 (Concurrency))

14. Dos hilos de un mismo proceso incrementan concurrentemente la misma variable compartida en memoria, sin emplear ningún mecanismo de sincronización. ¿Qué problema es más probable que ocurra?

  1. Un desbordamiento de pila (stack overflow) por exceso de llamadas anidadas.
  2. Una condición de carrera (race condition) con resultado no determinista.
  3. Una fuga de memoria (memory leak) por no liberar la variable compartida.
  4. Un error de tipos detectado por el compilador antes de ejecutar el programa.

Cuando varios hilos acceden y modifican una variable compartida sin sincronización, el resultado depende del orden de ejecución, lo que constituye una condición de carrera; las demás opciones no se derivan de este escenario. (Sebesta, Concepts of Programming Languages, cap. 13)

15. En un sistema, el proceso A retiene el recurso R1 y espera a que se libere el recurso R2, mientras que el proceso B retiene R2 y espera a que se libere R1; ninguno de los dos cede el recurso que tiene. ¿Qué condición de concurrencia describe esta situación?

  1. Inanición (starvation) de uno de los procesos.
  2. Exclusión mutua (mutual exclusion) sobre los recursos compartidos.
  3. Un interbloqueo (deadlock) entre los dos procesos.
  4. Una sección crítica compartida entre los dos procesos.

La espera circular en la que cada proceso retiene un recurso y espera otro retenido por el otro proceso es la definición de interbloqueo; la exclusión mutua es solo una de las condiciones necesarias para que ocurra, no la situación descrita en sí. (Sebesta, Concepts of Programming Languages, cap. 13)

16. ¿Qué mecanismo de sincronización se utiliza comúnmente para garantizar que solo un hilo a la vez acceda a una sección crítica compartida?

  1. Un iterador sobre una colección de datos.
  2. Una función de orden superior que recibe otra función.
  3. Un patrón de diseño singleton aplicado a una clase.
  4. Un semáforo o candado de exclusión mutua (mutex).

Los semáforos y mutex son los mecanismos clásicos para proteger secciones críticas y garantizar exclusión mutua entre hilos; las demás opciones no cumplen esa función. (Sebesta, Concepts of Programming Languages, cap. 13)

17. ¿Cuál de las siguientes NO forma parte de las cuatro condiciones necesarias de Coffman para que ocurra un interbloqueo (deadlock)?

  1. Prioridad de planificación round-robin entre los procesos.
  2. Exclusión mutua sobre al menos un recurso.
  3. Retención y espera de recursos adicionales.
  4. Espera circular entre los procesos involucrados.

Las condiciones de Coffman son exclusión mutua, retención y espera, no apropiación (no preemption) y espera circular; la política de planificación round-robin no es una de ellas. (E. G. Coffman, M. Elphick y A. Shoshani, 'System Deadlocks', ACM Computing Surveys, 1971)

18. Considere el siguiente fragmento de pseudocódigo: entero suma <- 0 Para i <- 1 hasta 4 hacer suma <- suma + i Fin Para ¿Cuál es el valor final de la variable suma al terminar el ciclo?

  1. 6
  2. 10
  3. 15
  4. 4

El ciclo acumula 1+2+3+4 = 10; el valor 6 resulta de detener la suma un paso antes (1+2+3) y el valor 15 de sumar un paso de más (1+2+3+4+5). (SICP, cap. 1 (procesos iterativos con acumulador); Sebesta, cap. 1)

19. Considere el siguiente fragmento de pseudocódigo: entero contador <- 0 Para i <- 1 hasta 10 hacer Si i MOD 3 = 0 entonces contador <- contador + 1 Fin Si Fin Para ¿Cuál es el valor final de la variable contador al terminar el ciclo?

  1. 4
  2. 10
  3. 3
  4. 2

Los múltiplos de 3 entre 1 y 10 son 3, 6 y 9, por lo que contador termina en 3; contarlos incorrectamente (incluyendo 10 o excluyendo uno de ellos) produce 4 o 2. (Sebesta, Concepts of Programming Languages, cap. 1 (estructuras de selección e iteración))

20. Considere el siguiente fragmento de pseudocódigo: entero total <- 0 Para i <- 1 hasta 3 hacer Para j <- 1 hasta 2 hacer total <- total + (i * j) Fin Para Fin Para ¿Cuál es el valor final de la variable total al terminar ambos ciclos?

  1. 21
  2. 9
  3. 12
  4. 18

La suma de i·j para i=1..3 y j=1..2 equivale a (1+2+3)×(1+2) = 18; el valor 21 resulta de sumar (i+j) en vez de multiplicar, y 9 o 12 resultan de recorrer solo una parte de los ciclos anidados. (Sebesta, Concepts of Programming Languages, cap. 1 (ciclos anidados))

21. Sobre la lista [1, 2, 3, 4, 5] se aplica primero la operación map con la función 'elevar al cuadrado' y, sobre el resultado, se aplica la operación filter conservando únicamente los valores mayores que 10. ¿Cuál es la lista resultante?

  1. [16, 25]
  2. [] (lista vacía)
  3. [9, 16, 25]
  4. [1, 4, 9, 16, 25]

map produce [1, 4, 9, 16, 25] y filter conserva solo los mayores que 10, es decir [16, 25]; la lista vacía resultaría de invertir el orden (filtrar antes de elevar al cuadrado) y las otras opciones surgen de omitir el filtro o usar un umbral incorrecto. (SICP, cap. 2 (map, filter, accumulate); Sebesta, cap. 15)

22. Se definen las clases Animal y Perro, donde Perro hereda de Animal. Ambas implementan el método hacerSonido(): Animal lo define retornando la cadena "..." y Perro lo sobrescribe retornando "Guau". En el código se declara una variable de tipo Animal que referencia un objeto instanciado de la clase Perro, y se invoca miVariable.hacerSonido(). Según el mecanismo de despacho dinámico, ¿qué valor se obtiene?

  1. "...", porque el método se resuelve según el tipo declarado de la variable (Animal) y no según el objeto real.
  2. "Guau", porque el despacho dinámico resuelve el método según la clase real del objeto, no según el tipo declarado de la referencia.
  3. Un error de compilación, porque un objeto Perro no puede asignarse a una variable de tipo Animal.
  4. La concatenación "...Guau", porque el programa ejecuta ambas versiones del método sobre el mismo objeto.

El despacho dinámico (dynamic binding) resuelve la llamada según la clase real del objeto en tiempo de ejecución (Perro), no según el tipo declarado de la referencia; asignar un Perro a una variable Animal es válido por la relación 'es-un' de la herencia. (Sebesta, Concepts of Programming Languages, cap. 12; Meyer, Object-Oriented Software Construction, 2a ed.)

23. Se aplica la operación reduce sobre la lista [2, 3, 4] con la función acumuladora f(acumulado, elemento) = acumulado * elemento, partiendo de un valor inicial de 2. ¿Cuál es el resultado final de la reducción?

  1. 24
  2. 11
  3. 48
  4. 12

La reducción calcula ((2×2)×3)×4 = 48; el valor 24 resulta de ignorar el valor inicial (2×3×4), 11 de sumar en vez de multiplicar, y 12 de detener la acumulación antes del último elemento. (SICP, cap. 2 (accumulate/reduce); Sebesta, cap. 15 (higher-order functions))

24. Un programador escribe el siguiente ciclo con la intención de sumar los números del 1 al 5, pero al ejecutarlo obtiene un resultado distinto del esperado (15): entero suma <- 0 entero i <- 1 Mientras i < 5 hacer suma <- suma + i i <- i + 1 Fin Mientras ¿Cuál es la causa del resultado incorrecto?

  1. La variable suma no se inicializa en 0 antes de comenzar la ejecución del ciclo completo.
  2. El ciclo Mientras nunca se ejecuta porque su condición inicial es falsa.
  3. El incremento i <- i + 1 se ejecuta antes que la suma, invirtiendo el orden de las operaciones.
  4. La condición i < 5 excluye el valor 5, por lo que el ciclo termina antes de sumarlo (debería ser i <= 5).

Con la condición i < 5 el ciclo se detiene cuando i llega a 5, dejando de sumar ese valor y obteniendo 10 en vez de 15; la inicialización, la condición inicial y el orden de las sentencias dentro del ciclo son correctos. (Sebesta, Concepts of Programming Languages, cap. 1 (condiciones de iteración))

25. Al depurar un programa mediante una traza de ejecución manual, ¿qué información se registra típicamente en cada paso?

  1. Los valores de las variables relevantes y el punto de control (línea o sentencia) alcanzado en ese paso.
  2. Los mensajes de error que genera el compilador antes de ejecutar el programa.
  3. El tiempo total, en milisegundos, que tarda el programa completo en ejecutarse.
  4. La cantidad de memoria RAM disponible en el equipo donde corre el programa.

Una traza de ejecución registra, paso a paso, los valores que toman las variables y el punto del código alcanzado, lo que permite localizar dónde el comportamiento se desvía de lo esperado. (Sebesta, Concepts of Programming Languages, cap. 1 (semántica operacional y seguimiento de estado))

26. Se tienen las variables enteras a <- 5 y b <- 8. Se ejecuta la siguiente secuencia de asignaciones: temp <- a a <- b b <- temp ¿Cuáles son los valores finales de a y b al terminar la secuencia?

  1. a = 5, b = 8.
  2. a = 8, b = 5.
  3. a = 8, b = 8.
  4. a = 5, b = 5.

temp guarda el valor original de a (5); luego a toma el valor de b (8) y b toma el valor guardado en temp (5), intercambiando los valores; las demás opciones surgen de omitir el uso de la variable temporal o de sobrescribir un valor antes de guardarlo. (Sebesta, Concepts of Programming Languages, cap. 1 (sentencia de asignación))

27. En la programación orientada a objetos, el principio que consiste en ocultar los detalles internos de un objeto y exponer únicamente una interfaz pública para interactuar con él se conoce como:

  1. Herencia
  2. Sobrecarga
  3. Encapsulamiento
  4. Polimorfismo

El encapsulamiento oculta el estado interno del objeto y expone solo una interfaz pública, principio derivado del ocultamiento de información propuesto por Parnas en 1972. (D. L. Parnas, On the Criteria To Be Used in Decomposing Systems into Modules, CACM 15(12), 1972.)

28. Cuando una clase 'Vehiculo' define atributos y métodos generales y una clase 'Automovil' los reutiliza y agrega comportamiento propio, la relación entre ambas clases se describe como:

  1. Automovil tiene-un Vehiculo
  2. Automovil es-un Vehiculo
  3. Automovil usa-un Vehiculo
  4. Automovil es-parte-de Vehiculo

La herencia establece una relación 'es-un' (is-a) entre subclase y superclase, no una relación de composición ('tiene-un') ni de uso. (Robert W. Sebesta, Concepts of Programming Languages, cap. 12.)

29. Caso práctico: un desarrollador tiene una superclase Figura con el método area() y dos subclases, Circulo y Rectangulo, cada una con su propia implementación de area(). En tiempo de ejecución, un arreglo de referencias de tipo Figura contiene objetos de ambas subclases y el programa invoca figura.area() dentro de un ciclo. ¿Qué mecanismo determina cuál implementación de area() se ejecuta para cada elemento?

  1. El orden de declaración de las subclases en el código fuente
  2. El tipo declarado de la variable de referencia en tiempo de compilación
  3. El tamaño en bytes de cada objeto instanciado en memoria
  4. El enlace dinámico, según el tipo real del objeto en tiempo de ejecución

El polimorfismo se implementa mediante enlace dinámico, que resuelve el método a ejecutar según el tipo real del objeto en tiempo de ejecución, no según el tipo declarado de la referencia ni el orden de declaración. (Sebesta, Concepts of Programming Languages, cap. 12 (Support for Object-Oriented Programming).)

30. De acuerdo con la caracterización clásica de Grady Booch, ¿cuáles son los cuatro pilares esenciales de la programación orientada a objetos?

  1. Abstracción, encapsulamiento, herencia y polimorfismo
  2. Modularidad, portabilidad, concurrencia y persistencia
  3. Encapsulamiento, recursividad, herencia y compilación
  4. Abstracción, herencia, recursividad y concurrencia

Booch resume las características esenciales de la POO en cuatro pilares: abstracción, encapsulamiento, herencia y polimorfismo. (Grady Booch, Object-Oriented Analysis and Design with Applications, 3a ed.)

31. ¿Cuál de las siguientes opciones NO corresponde a uno de los cuatro pilares de la programación orientada a objetos según Booch?

  1. Encapsulamiento
  2. Herencia
  3. Recursividad
  4. Polimorfismo

La recursividad es una técnica en la que una función se llama a sí misma, no uno de los pilares de la POO, que son abstracción, encapsulamiento, herencia y polimorfismo. (Grady Booch, Object-Oriented Analysis and Design with Applications, 3a ed.)

32. Caso práctico: en una clase, un atributo se declara con el modificador de acceso 'protegido' (protected) en lugar de 'privado' (private). ¿Qué consecuencia tiene esta decisión sobre el encapsulamiento respecto de las subclases?

  1. Ninguna clase, ni siquiera las subclases, puede acceder al atributo
  2. Las subclases pueden acceder al atributo directamente, pero el resto del programa no
  3. Cualquier clase del programa puede acceder libremente al atributo, igual que si fuera público
  4. Solo los métodos de la misma clase pueden acceder al atributo, igual que si fuera privado

El modificador protegido relaja el encapsulamiento estricto permitiendo el acceso desde subclases, a diferencia de privado (solo la propia clase) y público (todo el programa). (Sebesta, Concepts of Programming Languages, cap. 11-12 (modificadores de acceso y encapsulamiento).)

33. Caso práctico: un equipo de desarrollo detecta que dos clases, Empleado y Cliente, comparten los atributos nombre y correo, y el método actualizarDatos(), pero no tienen ninguna otra relación conceptual entre sí. ¿Qué acción de diseño resuelve mejor la duplicación de código sin forzar una relación 'es-un' artificial?

  1. Declarar Cliente como subclase de Empleado para reutilizar directamente su código
  2. Copiar el método actualizarDatos() en cada clase para mantenerlas independientes
  3. Convertir todos los atributos de ambas clases en variables globales del programa
  4. Extraer los atributos y el método comunes a una clase base o interfaz que ambas compartan

Cuando dos clases comparten comportamiento sin relación conceptual 'es-un', la práctica recomendada es extraer una superclase o interfaz común, evitando duplicación sin forzar una jerarquía de herencia artificial. (Grady Booch, Object-Oriented Analysis and Design with Applications; Bertrand Meyer, Object-Oriented Software Construction, 2a ed.)

34. El mecanismo por el cual una llamada a un método se resuelve en tiempo de ejecución según el tipo real del objeto, y no según el tipo declarado de la variable, se conoce como:

  1. Enlace dinámico (dynamic binding)
  2. Enlace estático (static binding)
  3. Sobrecarga de métodos (method overloading)
  4. Herencia múltiple

El polimorfismo en tiempo de ejecución se apoya en el enlace dinámico, que resuelve el método según el tipo real del objeto receptor, no en tiempo de compilación. (Sebesta, Concepts of Programming Languages, cap. 12.)

35. En programación orientada a objetos se distinguen dos formas de polimorfismo: la sobrecarga (overloading), resuelta en tiempo de compilación según la firma del método, y la sobreescritura (overriding), resuelta en tiempo de ejecución mediante enlace dinámico. Si una subclase redefine con la misma firma un método ya definido en su superclase para especializar su comportamiento, ¿qué forma de polimorfismo se está aplicando?

  1. Sobrecarga (overloading), resuelta en tiempo de compilación
  2. Encapsulamiento, porque se oculta la implementación original de la superclase
  3. Sobreescritura (overriding), resuelta mediante enlace dinámico en tiempo de ejecución
  4. Herencia múltiple, porque intervienen dos clases con el mismo método

Redefinir un método con la misma firma en una subclase para especializar su comportamiento es sobreescritura (overriding), resuelta mediante enlace dinámico en ejecución; la sobrecarga implica firmas distintas resueltas en compilación. (Sebesta, Concepts of Programming Languages, cap. 12 (overloading vs. overriding, dynamic binding).)

Comienza gratis