Programación Modular
Programación Modular
Programación modular
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.
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.
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
1
Programación 1 CLASE 6
figura 1), como si fuera el organigrama de una empresa (López Román, 2003).
Subprograma
principal
Módulo I Módulo II
Módulo.
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 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).
2
Programación 1 CLASE 6
Cuando el enfoque de diseño descendente se utiliza de manera conjunta con la técnica del
pseudocódigo, se logra una herramienta de diseño de algoritmos (programas) muy poderosa.
A continuación se explica el procedimiento para hacerlo:
Llamar NombreModulo
Donde:
✓ Constantes
✓ Tipos
✓ Variables
Que son globales, es decir, se pueden utilizar en cualquier módulo del algoritmo. Es
opcional; es decir, puede estar presente o no.
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)
El proceso de segmentación consiste en hacer una abstracción del problema, del cual se tiene
inicialmente el panorama general. Enseguida se procede a “descomponer” o “dividir” el
problema en partes pequeñas y simples (ver figura 3).
Modularización funcional.
Los bloques de código independientes del programa principal que se han definido como
módulos tienen siempre una connotación funcional. Esto quiere decir que estos segmentos
realizan alguna tarea específica por lo que cuando se definen estos subprogramas, lo que se
hace es identificar actividades concretas y desarrollar el subprograma para resolverlas.
Una ventaja al dar solución a los problemas mediante la modularización es que se pueden
“encapsular” las distintas tareas que se quiere realice el programa, logrando así colocar como
una unidad todas las instrucciones relevantes para una sección específica del programa, lo que
también permite que cuando existe la necesidad de realizar algún cambio en dichas
instrucciones se tenga claridad a donde dirigirse para hacer ese cambio y no haya necesidad de
analizar de manera completa todo el desarrollo, lo que hace que los programas sean fáciles de
probar y mantener.
4
Programación 1 CLASE 6
Lo anterior permite que si se logra tener un programa que resuelva una tarea específica y este
proceso está suficientemente probado, entonces una vez que está programado, es posible
usarlo tantas veces como sea necesario con la única condición de conocer los datos que lo
alimentan y los resultados que arroja. Por otro lado, esta condición evita que se repita el
código muchas veces y que si se comete un error de programación en este segmento del
código solo se tenga que corregir una vez.
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.
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.
El objetivo en el diseño modular es conseguir módulos tan cohesivos como sea posible.
Muchas veces esto no es posible al cien por ciento pero siempre debe pretenderse desarrollar
módulos con alta cohesión.
5
Programación 1 CLASE 6
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.
Otro aspecto que destaca al usar modularidad es el acoplamiento que mide el grado de
relación de un módulo con los demás. Con un menor acoplamiento el módulo es más sencillo
de diseñar, programar, probar y mantener.
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
6
Programación 1 CLASE 6
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).
Variables locales.
Las variables locales sólo existen en un ámbito determinado del programa, por ejemplo en un
subprograma o en un bloque de sentencias. Solo pueden ser utilizadas en el módulo donde
fueron definidas (ver figura 7).
Entonces si son analizados los conceptos de variables globales y locales, es posible resumir que
cuando se usan variables locales, éstas son independientes de las globales y de las de otros
módulos.
7
Programación 1 CLASE 6
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.
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.
Los parámetros actuales y los parámetros formales no necesitan tener los mismos nombres, ya
que se corresponden por tipo y posición.
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.
En este caso el método recibe una copia del valor que se le pasa. La variable original
(parámetro actual) no cambia de valor, independientemente de que en el método se cambie el
contenido del parámetro formal.
Explicación.
8
Programación 1 CLASE 6
Cuando se llama al Módulo cambiar, se conectan X y Y vía parámetro por valor, lo que hace
que el valor de X se le asigne a Y; de ahí en adelante X y Y no tienen ninguna relación.
En el paso por referencia no se pasa una copia del valor sino la identificación de la zona de
memoria donde se almacena dicho valor. Por esta razón al trabajar dentro 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:
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.
9
Programación 1 CLASE 6
Cuando existe un cálculo que será usado de manera repetida a lo largo del programa en
distintos momentos se implementan funciones que el usuario define. Una función es muy
parecida a los módulos, con la diferencia de que sólo devuelve un valor de un tipo de dato
simple.
El nombre de la función puede estar seguido por uno o más parámetros encerrados entre
paréntesis, a continuación se detalla cómo son definidas:
Sintaxis:
Declaraciones
Acción 1
…..
Acción N
Donde:
Parámetros: Es la lista de variables de entrada que sirven como base para hacer los
cálculos en la función.
Para llamar una función se indica el nombre de la función y entre paréntesis el parámetro o
parámetros que se envían (ver Anexo II).
6. Módulos de programa en C.
10
Programación 1 CLASE 6
Función principal.
Todo programa en C contiene una función principal o función main, la cual es la encargada de
llevar el control de ejecución del programa (secuencia de ejecución de instrucciones) y de
llamar a ejecución a las funciones correspondientes en los puntos del programa donde se
necesiten.
Cuando una función invocadora realiza una llamada a otra función, el control se transfiere de
la primera a la segunda, lo que quiere decir que, la función que pasa ahora a ejecutarse es la
segunda. Adicionalmente la función invocadora puede trasferir ciertos datos a la función
invocada en el momento de realizar la llamada a estos datos se les denomina argumentos de
entrada de la función.
Cuando la función invocada concluye su ejecución debe devolver el controla a la función que la
ha llamado y adicionalmente la función invocada puede devolver un resultado o dato a la
invocadora, a este dato se le denomina salida de la función.
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.
11
Programación 1 CLASE 6
Prototipo de la función.
12
Programación 1 CLASE 6
Cuerpo de la función.
Declaraciones Enunciados
Donde:
Un bloque es un enunciado compuesto que incluye declaraciones. Las variables pueden ser
declaras en cualquier bloque y los bloques pueden estar anidados. Bajo ninguna circunstancia
puede ser defina una función en el interior de otra función.
Existen varias formas de regresar el control al punto desde el cual se invocó a una función.
Todas las variables declaradas en las definiciones de funciones son variables locales lo que
significa que son conocidas solo en la función en la cual están definidas (Deitel & Deitel, 2004).
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.
13
Programación 1 CLASE 6
La mayor parte de las funciones tienen una lista de parámetros que proporcionan la forma de
comunicar información entre funciones. Los parámetros de una función también son variables
locales.
Llamadas de función.
Las formas de invocar funciones en muchos lenguajes de programación son la llamada por
valor y la llamada por referencia. Para el caso de que los argumentos se pasan en llamada por
valor, se efectúa una copia del valor del argumento y ésta se pasa a la función llamada. Las
modificaciones a la copia no afectan al valor original de la variable de la función invocadora. –
cuando un argumento es pasado en llamada por referencia, el llamador de hecho permite que
la función llamada modifique el valor original de la variable (Deitel & Deitel, 2004).
Todas las funciones disponen de una zona de memoria donde se almacenan las variables
definidas dentro del cuerpo de una función, las variables que actúan como argumentos
formales, así como distintos resultados que se vayan produciendo a lo largo de ejecución de la
misma.
En el momento que una función comienza a ejecutarse se realiza una reserva de memoria para
almacenar todos los datos mencionados, cuando la función finaliza su ejecución se libera dicha
zona de memoria y por consiguiente se pierden los datos almacenados en ella.
La llamada por valor debería se utilizada siempre que la función llamada no necesite modificar
el valor de la variable original de la función invocadora. Esto 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).
En muchos casos cuando se requiere modificar una o más variables del llamador o bien es
necesario pasar un objeto de datos grande y evitar así la sobrecarga de pasar un objeto en
llamada por valor, C permite “simular” las llamadas por referencia.
Es frecuente emplear apuntadores y el operador de indirección 4para simular las llamadas por
referencia 5(Deitel & Deitel, 2004).
14
Programación 1 CLASE 6
C implementa esta funcionalidad con el uso de referencias. Una referencia es un alias a una
localización de memoria, es decir permite referirse a la misma zona de almacenamiento que
otro valor. El paso de valores por referencia permite tener parámetros que se refieran a las
mismas posiciones de memoria que los parámetros reales usados en al llamada. Por esta
razón, toda modificación que se realice sobre los parámetros formales pasados por referencia
se aplicará a los parámetros reales. Para indicar que un determinado parámetro se pasa por
referencia, el nombre del parámetro debe ir precedido del símbolo &.
Al simular estas llamadas lo que se hace es pasar a la función las direcciones de los argumentos
mediante el operador de dirección “&” a la variable que modificara el valor (ver anexo IV).
✓ En el paso por valor se realiza una copia del valor del parámetro en el momento de la
llamada. Para datos de gran tamaño esto puede representar un problema de
eficiencia.
✓ 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.
GCC, the GNU Compiler Collection. (s.f.). Recuperado junio de 2012, de http://gcc.gnu.org/
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.
8. WebGrafía
5Los 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.
15
Programación 1 CLASE 6
chrome-
extension://efaidnbmnnnibpcajpcglclefindmkaj/http://ri.uaemex.mx/bitstream/handle/20.500
.11799/69946/secme-19449_1.pdf?sequence=1
9. ANEXOS
Anexo I
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.
16
Programación 1 CLASE 6
Anexo II
#include <stdio.h>
printf ("Cuales son los valores de x y de y");scanf ("%d %d", &x, &y);
if (x>0 && y>0 && x>y){
f=factorial(x) / (factorial (y) * factorial (x-y));printf("El valor de F es: %.2f", f);
}
else
{
printf("Números incorrectos \n");
}
}
fact=1; if (n!=0)
{
for (i=1; i<=n; i++)
fact=fact*i;
}
return fact;
}
Anexo III
Elaborar un programa que solicte al usuario dos números enteros y evalué la función
Anexo IV
18
Programación 1 CLASE 6
#include <stdio.h>
main ()
int num=5;
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;
19