Programación Modular
Programación Modular
Facultad de Ingeniería
Programación Modular
Octubre 2017
Contenido
Ubicación del material ...................................................................................................................3
Programación modular.......................................................................................................................4
Introducción ...................................................................................................................................4
1. Diseño descendente. ..............................................................................................................5
1.1 Módulo. ................................................................................................................................5
1.2 Diseño descendente con pseudocódigo. ..............................................................................6
2. Proceso de modularización o segmentación. .........................................................................7
2.1 Modularización funcional. ....................................................................................................8
3. Cohesión y acoplamiento. ......................................................................................................9
4. Alcance de las variables. .......................................................................................................10
4.1 Variables globales. ..............................................................................................................11
4.2 Variables locales. ................................................................................................................11
4.3 Parámetros. ........................................................................................................................12
5. Funciones definidas por el usuario. ......................................................................................14
6. Módulos de programa en C. .................................................................................................15
6.1 Función principal. ...............................................................................................................16
6.2 Funciones. ..........................................................................................................................16
6.3 Llamadas de función. ..........................................................................................................19
7. Bibliografía ...........................................................................................................................21
8. ANEXOS ................................................................................................................................22
8.1 Anexo I................................................................................................................................22
8.2 Anexo II...............................................................................................................................23
8.3 Anexo III..............................................................................................................................24
Ubicación del material
Unidad de Aprendizaje:
Programación Básica
Clave:
L41205, L41304
Horas teóricas:
2 horas
Horas prácticas:
2 horas
Créditos:
8 créditos
Tipo de curso:
Curso presencial
Núcleo de formación:
Sustantivo
Ninguna
Introducción
La programación modular está presente desde los primeros tiempos de la
programación como disciplina. De hecho existía programación modular antes de
existiera programación estructurada para poder abordar problemas complejos.
Cuando se requieren resolver problemas más complejos, en los que el número de
instrucciones aumenta, existen técnicas que permiten resolverla de forma eficiente
estos problemas, facilitando al programador la construcción de la solución.
Se puede definir a la programación modular como aquella que usa el concepto de
dividir un problema complejo en subproblemas más pequeños, hasta que estos
sean fáciles de tratar y resolver por separado. Así la solución de los subproblemas
en conjunto dan como resultado la solución del problema completo (López
Román, 2003).
Aplicando este principio a la hora de hacer un programa, entonces habría que
dividir el programa en “subprogramas” que realicen tareas específicas. Es
importante considerar que para poner en práctica la modularización, es necesario
un mecanismo que permita aplicarla en los lenguajes de programación; este
mecanismo existe prácticamente en todos los lenguajes y consiste en la
posibilidad de definir tareas específicas como módulos de código independientes
del programa principal. En consecuencia estos módulos de código independientes
del programa deben poder invocarse desde el programa o módulo principal para
que empiecen a trabajar y deben acabar devolviendo el control al programa o
módulo principal cuando terminen de ejecutarse.
La programación modular permite:
a) Dividir la complejidad de un problema convirtiendo problemas complejos en
un conjunto de problemas más simples y por tanto más sencillos de
implementar.
b) Reutilizar el código de un programa en cualquier momento de la ejecución
del mismo.
Evidentemente la división de un problema en módulos no tiene por qué ser ni
única ni obligatoria, pero si es claramente aconsejable a la hora de abordar un
problema para lo cuál que se aplican diversos conceptos y técnicas entre las que
se encuentran el diseño descendente, el proceso de modularización y el paso de
parámetros, por mencionar algunos. A continuación se abordaran cada uno de
ellos.
4
1. Diseño descendente.
Es una técnica que permite diseñar la solución de un problema con base en la
modularización o segmentación dándole un enfoque de arriba hacia abajo (Top
Down Design). Esta solución permite dividir el problema en módulos que se
estructuran e integran jerárquicamente (ver figura 1), como si fuera el organigrama
de una empresa (López Román, 2003).
Subprograma
principal
Módulo I Módulo II
1.1 Módulo.
Es un segmento, rutina, subrutina, subalgoritmo o procedimiento que puede ser
definido dentro de un algoritmo mayor con el propósito de ejecutar una tarea
específica, pudiendo ser llamado o invocado desde el módulo principal cuando se
requiera.
Este enfoque de segmentación o modularización es útil:
Cuando existe un grupo de instrucciones o una tarea específica que debe
ejecutarse en más de una ocasión.
Cuando un problema es complejo o extenso, entonces la solución se
“divide” o “segmenta” en módulos que ejecutan “partes” o tareas
específicas.
Dicha solución se organiza y divide en partes más pequeñas que sean fácilmente
manejables y que, lógicamente, puedan ser separadas; así cada una de estas
partes se dedica a ejecutar una determinada tarea, lo que redundará en una
mayor concentración, entendimiento y capacidad de solución a la hora de diseñar
la lógica de cada una de estas.
Las partes en las que se divide una empresa (funcionalmente separadas) son el
equivalente a los módulos o segmentos del algoritmo, algunos de ellos son
módulos directivos o de control, que son los que se encargarán de distribuir el
5
trabajo a los demás módulos, de tal forma que se puede diseñar una especie de
organigrama que indique la estructura general de un algoritmo (López Román,
2003).
6
Parte 4. Se tiene uno o más módulos o funciones subordinados, son opcionales
(ver figura 2).
Declaraciones globales
(opcional)
Módulo principal
(obligatorio)
II. Se toma este módulo y se busca la forma de dividirlo en otros módulos más
pequeños, que ejecuten tareas o funciones específicas. Normalmente serán
las mismas funciones que se desea que ejecute el algoritmo, lo que permite
de una forma simple definir los módulos, y de esta forma dividir el problema
en partes más manejables.
III. Se repite el paso anterior para cada módulo nuevo definido, hasta llegar a
un nivel de detalle adecuado, es decir, hasta hacer que cada módulo
ejecute una tarea específica, claramente definida y que el diseño y la
codificación de la lógica del mismo resulte fácil (Ver anexo I).
7
Problema en términos de
la solución general
8
Subprogramas, subrutinas o procedimientos, si pueden devolver más de un
valor.
Funciones, si devuelven un único valor a través de su identificador.
La estructura del programa en función de sus módulos se puede representar con
los denominados diagramas de estructura, que son herramientas típicas del
diseño estructurado y forman parte de una completa metodología de trabajo. Estos
diagramas son una representación en forma de árbol jerárquico de la estructura
del software, donde los diferentes módulos se representan como cajas
rectangulares. La relación de invocaciones de unos módulos a otros se
representan en estos diagramas por medio de flechas y el sentido de las flechas
representa el orden de invocación de los módulos.
3. Cohesión y acoplamiento.
Los módulos deben cumplir dos características básicas para ser candidatos a una
buena división del problema.
Alta cohesión: las instrucciones contenidas dentro de un módulo deben
contribuir a la ejecución de la misma tarea.
Bajo acoplamiento: a dependencia entre módulos debe ser mínima. Lo que
implica que no debe haber dantos compartidos entre los módulos (ver figura
4).
Por lo general se espera que cada módulo de código realice una sola tarea; es
decir, todos los componentes de un módulo (sentencias) deben ir dirigidos a
resolver un y sólo un problema. A esta propiedad se le denomina cohesión y se
dice que los módulos deben ser cohesivos.
ALTA
Cohesión
BAJO
Acoplamiento
9
La cohesión tiene que ver con que cada módulo del sistema se refiera a un único
proceso o entidad. A mayor cohesión el módulo en cuestión será más sencillo de
diseñar, programar, probar y mantener.
En el diseño estructurado, se logra alta cohesión cuando cada módulo (función o
procedimiento) realiza una única tarea trabajando sobre una sola estructura de
datos. Una prueba que se recomienda hacer a los módulos funcionales para ver si
son cohesivos es analizarlos y describirlos con una oración simple que contenga
un solo verbo activo. Si existe más de un verbo presente en la descripción del
procedimiento o función, se debía plantear más de un módulo, y volver a hacer la
prueba con los módulos resultantes (ver figura 5).
Estadísticas
10
4.1 Variables globales.
Son las que son accesibles desde cualquier punto del programa y se pueden usar
desde cualquier módulo o subprograma, esto lleva a considerar que la variable
puede usarse en cualquier parte del programa y su valor se puede alterar
incontroladamente, y si posteriormente es necesario usar la variable en otra parte
del programa con su valor original, se tendrá un error. El punto donde se da el
error es fácil de localizar, pero no lo es tanto el origen del mismo. Este tipo de
efectos colaterales produce errores cuyo origen es difícil de trazar y localizar: La
programación modular sugiere que se evite el uso de variables globales (ver figura
6).
Algoritmo GLOBALES
num: Entero Declaración de num como variable global
Módulo principal
num ← 0
Llamar resultado
Escribir num Todos los módulos reconocen la variable
Fin Módulo principal num como global y la pueden cambiar
Módulo resultado
El resultado al num ←1
Fin Módulo resultado
escribir el valor
de num sería 1
11
Algoritmo LOCALES
num:Entero Declaración de num como variable global
Módulo principal
num ← 0
Llamar resultado
Escribir num
Fin Módulo principal
4.3 Parámetros.
Entre los módulos que componen la estructura completa de un problema, se
establece una serie de comunicaciones a través de determinadas interfaces
(llamadas a los módulos) que permiten el paso de información de un módulo a otro
así como la trasferencia del control de la ejecución del programa.
Un método puede aceptar información para usarla en su cuerpo de sentencias.
Esta información es suministrada en forma de literales, variables pasadas al
método a través de su cabecera y cada uno de estos elementos de información se
denomina parámetro.
De manera más formal se puede definir un parámetro como un valor que se pasa
al método cuando éste es invocado. La lista de parámetros en la cabecera (al
inicio) de un método especifica los tipos de los valores que se pasan y los
nombres por los cuales el método se referirá a los parámetros en la definición del
método.
En la definición del método los nombres de los parámetros aceptados se
denominan parámetros formales.
En las invocaciones al método desde algún punto del programa, los valores
que se pasan al método se denominan parámetros actuales (reales).
Los parámetros actuales y los parámetros formales no necesitan tener los mismos
nombres, ya que se corresponden por tipo y posición.
12
Cuando se invoca un método, los parámetros se colocan entre paréntesis, si no se
necesitan parámetros se usan paréntesis vacíos.
En relación con los parámetros, un aspecto importante, que es necesario conocer
en cualquier lenguaje, es como se realiza el paso de los parámetros actuales a los
formales, a lo que se le conoce comúnmente como el problema del paso de
parámetros. Hay dos posibles formas por valor o por referencia.
13
del módulo con la entidad pasada por referencia se está manipulando el mismo
valor que se utiliza fuera. Para efectos prácticos si se realiza una modificación de
ese valor dentro del módulo, la modificación se mantiene al salir del mismo y la
diferencia con el paso por valor, es que el que el módulo maneja una copia del
valor original, y las modificaciones realizadas dentro del método no afectan a la
variable externa.
Explicación:
Se define a la variable X en el módulo principal, la cual tiene su contenido en la
memoria, y se le coloca 0.
Contenido
X
0
Cuando se llama al Módulo Cambiar, se conecta X y Y vía parámetro por
referencia, lo que hace que sean sinónimos, es decir, que Y utilice la misma
dirección de memoria que X.
Contenido
X
0
Y
14
Sintaxis:
Función Nom_Función (Parámetros): Tipo de dato
Declaraciones
Acción 1
…..
Acción N
Fin Función Nom_Función
Donde:
Función: Indica que se está definiendo una función.
Declaraciones: se pueden definir constantes y variables.
Nom_Función: Es el nombre de la función que será manejada como
cualquier variable de tipo simple.
Parámetros: Es la lista de variables de entrada que sirven como base
para hacer los cálculos en la función.
Tipo de dato: Es el tipo de dato que regresa la función.
6. Módulos de programa en C.
En C la técnica de programación modular se implementa mediante la utilización de
funciones. Una función permite agrupar un conjunto de instrucciones en un bloque
que típicamente realizara una tarea elemental. Por lo general en C, los programas
se escriben combinando nuevas funciones que el programador diseña, con
funciones “preempacadas”, disponibles en la biblioteca estándar de C (Deitel &
Deitel, 2004).
Como se indicó anteriormente para dar solución a un problema particular es
necesario identificar previamente las tareas elementales que debe realizar el
problema, y posteriormente estas se implementarán como funciones.
Las funciones permiten modularizar un programa y se invocan mediante una
llamada de función que específica el nombre de la misma y proporciona
15
información (en forma de argumentos) que la función llamada necesita a fin de
llevar a cabo la tarea que tiene designada.
6.2 Funciones.
Como ya se ha mencionado anteriormente existen varias ventajas al modularizar e
implementar funciones:
Los programas son más sencillos de implementar y corregir, puesto que
son tareas básicas compuestas de unas pocas líneas de instrucciones.
Fomenta la reutilización.
Es posible crear programas partiendo de funciones estandarizadas que
ejecuten tareas específicas, en vez de desarrollarlos usando código
personalizado.
Evitar la repetición de código, ya que agrupar código en forma de funciones
permite que se ejecute dicho código desde distintas posiciones en un
programa, simplemente llamando dicha función.
Se puede llamar a una función desde diferentes partes de un programa.
16
Se pueden trasferir un conjunto de datos distinto cada vez que se llama a la
función (entorno de ejecución de una función), obteniendo resultados
diferentes en cada uno de los casos.
#include <stdio.h>
17
Prototipo de la función.
Un prototipo de función le indica al compilador el tipo de dato que regresa la
función, el número de parámetros que la función espera recibir, los tipos de dichos
parámetros, y el orden en el cual se esperan dichos parámetros. El compilador
utiliza los prototipos de funciones para verificar las llamadas de función.
Cuerpo de la función.
El formato de una definición de función como se ha mostrado en el ejemplo
anterior es:
tipo_de_valor_de_regreso nombre_la_función (lista de parámetros)
{
Declaraciones
Enunciados
}
Donde:
tipo_de_valor_de_regreso: El tipo de valor de regreso el valor que una
función devolverá.1
nombre_de_la_función: es cualquier identificador valido2.
lista_de_parámetros: lista separada por comas que contiene las
declaraciones de los parámetros recibidas por la función al ser llamada 3.
Declaraciones y Enunciados: forman el cuerpo de la función. El cuerpo de la
función también se conoce como un bloque.
1
Un tipo de valor de regreso no especificado será siempre supuesto por el compilador como int.
2
Un identificador válido es cualquier nombre formado por letras y números, excluyendo palabras reservadas
del propio lenguaje como son por ejemplo if, while, void, int, etc.
3
Si una función no recibe ningún valor, la lista de parámetros es void. Para cada parámetro deberá ser
enlistado de forma explícita un tipo, a menos de que el parámetro sea del tipo int.
18
Existen varias formas de regresar el control al punto desde el cual se invocó a una
función.
a) Si la función no regresa un resultado, el control sólo se devuelve cuando se
llega a la llave derecha que termina la función, o al ejecutar el enunciado
return;
19
evita efectos colaterales accidentales que obstaculizan de forma importante el
desarrolla de sistemas correctos y confiables de software. La llamada por
referencia debe ser utilizada solo en funciones llamadas confiables, que necesitan
modificar la variable original (Deitel & Deitel, 2004).
Al realizar llamadas por valor se realiza una copia del valor de la variable y esta
copia se pasa a la función llamada. De tal forma que los cambios a la copia de la
función llamada no afectan el valor contenido en la variable original (ver anexo III).
En C, todas las llamadas son llamadas por valor. Sin embargo es posible simular
la llamada por referencia mediante la utilización de operadores de dirección y de
indirección (Deitel & Deitel, 2004).
4
Referirse a un valor a través de un apuntador se conoce como indirección.
5
Los apuntadores son variables que contienen direcciones de memoria como sus valores. Los nombres de
las variables se refieren directamente a un valor y un apuntador se refiere indirectamente a un valor.
20
En los parámetros pasados por valor, si se hacen cambios a los parámetros
formales, los parámetros originales no son modificados.
En los parámetros pasados por referencia, la llamada debe usar como
parámetros reales valores de otra forma no podrán ser modificados.
En el paso por referencia lo que se copia es una dirección aunque el
parámetro en cuestión se refiera a un tipo estructurado (Fatos, Martin Prat,
Vazquez, Gómez, & Molinero, 2006)
7. Bibliografía
Deitel, H., & Deitel, P. (2004). Como programar en C/C++ y Java. México: Prentice
Hall.
Fatos, X., Martin Prat, A., Vazquez, P.-P., Gómez, J., & Molinero, X. (2006).
Programación en C++ para ingenieros. Madrid: Thomson.
Muñoz Caro, C., Niño Ramos, A., & Vizcaíno Barceló, A. (2002). Introducción a la
Programación con Orientación a Objetos. Madrid: Prentice Hall.
21
8. ANEXOS
8.1 Anexo I
Se desea calcular el área y perímetro de distintas figuras geométricas (cuadrado,
rectángulo, circulo y triangulo). Es claro el objetivo, sin embargo dar respuesta a
cada uno de los planteamientos requiere la instrumentación de tareas de manera
específica.
Aplicando la técnica de modularización es claro que se tiene identificado el
conjunto de fórmulas asociado para realizar los cálculos correspondientes de
acuerdo a la figura de la que se trate.
Entonces es posible plantear el siguiente esquema para abordar el problema:
Cuadrado
Rectángulo
Figuras
geométricas
Círculo
Triángulo
Así cada módulo hace una tarea simple, clara y específica y entonces se puede
diseñar fácilmente. Y para el caso que algún módulo requiere de otros
subordinados estos se van agregando en esta estructura jerárquica.
Cuadrado
Rectángulo
Figuras
geométricas
Círculo Equilátero
Triángulo Isóceles
Escaleno
22
8.2 Anexo II
Implementación de una función en pseudocódigo
Elaborar un algoritmo que solicite dos enteros y evalué la función
𝑥!
𝑓=
𝑦! ∗ (𝑥 − 𝑦)!
Donde los valores de x y y deben ser mayores a cero
Algoritmo CALCULA_F
Módulo Principal
Declaraciones
Variables
X, Y tipo entero
F tipo real
Escribir “Cuales son los valores de x, y”
Leer X, Y
Si (X>0 y Y>0 y X>=Y) entonces
F=Factorial(X) / (Factorial(Y) * Factorial(X-Y))
Escribir “El valor de F es: “, F
Otro
Escribir “Números incorrectos”
Fin Si
Fin Módulo Principal
23
8.3 Anexo III
Implementación de una función en C
Elaborar un programa que solicte al usuario dos números enteros y evalué la
función
𝑥!
𝑓=
𝑦! ∗ (𝑥 − 𝑦)!
Donde los valores de x y y deben ser mayores a cero
#include <stdio.h>
int factorial(int);
main(){
int x, y;
float f;
fact=1;
if (n!=0)
{
for (i=1; i<=n; i++)
fact=fact*i;
}
return fact;
}
24
8.4 Anexo IV
#include <stdio.h>
main ()
{
int num=5;
printf(“El valor original del numero es: %d\n”,num);
num=potencia(num);
printf(“El nuevo valor de numero aplicada la función con paso por valor es: %d\n”, num);
return 0;
}
int potencia(int x)
{
return x*x*x;
}
#include <stdio.h>
main ()
{
int num=5;
printf(“El valor original del numero es: %d\n”,num);
num=potencia_ref (&num);
printf(“El nuevo valor de numero aplicada la función con paso por referencia es: %d\n”, num);
return 0;
}
25