5. Modularidad
Un módulo es un componente de
un sistema más grande y opera dentro del sistema independientemente de las
operaciones de otros componentes.
La modularidad es una opción
importante para la escalabilidad y comprensión de programas, además de ahorrar
trabajo y tiempo en el desarrollo.
La modularidad es la capacidad
que tiene un sistema de ser estudiado, visto o entendido como la unión de
varias partes que interactúan entre sí y que trabajan para alcanzar un objetivo
común, realizando cada una de ellas una tarea necesaria para la consecución de
dicho objetivo. Cada una de esas partes en que se encuentre dividido el sistema
recibe el nombre de módulo. Idealmente un módulo debe poder cumplir las
condiciones de caja negra, es decir, ser independiente del resto de los módulos
y comunicarse con ellos (con todos o sólo con una parte) a través de unas
entradas y salidas bien definidas. (google, 2019)
Módulo: Es aquél que está
constituido por una o varias instrucciones físicamente contiguas y lógicamente
encadenadas, las cuales se pueden referenciar mediante un nombre y pueden ser
llamadas desde diferentes puntos de un programa. Un módulo puede ser:
• Un programa
• Una función
• Una subrutina (o
procedimiento)
5.1 Declaración y uso de módulos
Sintaxis para declarar un
módulo
Tipo Nombre (lista de
parámetros) //Cabecera de la función
{Declaraciones Instrucciones
//Cuerpo de la función
return valor;
}
Donde tipo es el tipo del dato
de salida, nombre es un identificador que representa el nombre de la función,
lista de parámetros es una lista de parámetros separados por comas, donde cada
parámetro se declara como en una declaración de variables normal, y valor es
aquel dato que regresaremos y debe coincidir con el tipo declarado al inicio.
Ámbito de un identificador:
Conjunto de sentencias donde puede utilizarse ese identificador. Reglas para el
cálculo del ámbito de un identificador:
1. Un identificador declarado
en un bloque es accesible únicamente desde ese bloque y todos los bloques
incluidos en él (se considera local a ese bloque). Un parámetro formal se
considera también una declaración local al bloque de la función. 2. Los identificadores
declarados fuera de cualquier bloque se consideran globales y pueden ser
utilizados desde cualquier punto del programa.
3. Cuando tenemos un bloque
dentro de otro bloque y en ambos se declaran identificadores con el mismo
nombre, el del bloque interno "oculta" al del bloque externo. (En C++
se admite la declaración de variables en cualquier bloque).
Reglas de uso de funciones:
• En una función sólo se deben
utilizar variables locales a la función o parámetros (que también son variables
locales). Las variables globales no se deben utilizar nunca.
• La razón es porque de esta
manera la función es independiente del programa principal.
• La independencia permite que
sea más fácil hacer cambios al programa, que la función pueda ser reutilizada en
otros programas y que sea más fácil trabajar en equipo. (Acosta, 2017)
5.2 Paso de parámetros y
argumentos
Parámetros
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.
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.
a) Paso por valor:
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.
b) Paso por referencia:
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.
5.3 Implementación
Modularidad en Java
En los lenguajes orientados a
objetos, como Java, el concepto esencial es el de clase, y los programas consisten
básicamente en conjuntos de declaraciones de clases. En la mayoría de los
lenguajes OO, existen,sin embargo, mecanismos para agrupar las clases
relacionadas en conjuntos de clases, asimilables a los
módulos de los lenguajes no
OO.
En Java, cabe destacar, en
esta línea, las siguientes posibilidades:
• Compilación separada
• Packages y restricciones de
acceso
Compilación separada
en Java
• En Java, una unidad de
compilación es un archivo de extensión .java que contiene una o varias
declaraciones de clases y/o interfaces. Cada unidad de compilación puede ser
traducida independientemente de otras.
• La traducción de un .java produce un archivo
con código intermedio (de extensión .class) por cada clase contenida en el
archivo .java original.
• Los archivos .class son
interpretables con el interprete de código intermedio de Java.
• Las declaraciones de una
unidad de compilación son visibles desde otras unidades de compilación, siempre
y cuando al traducir esas otras unidades se tenga acceso los archivos .class
obtenidos de traducir la primera.
Packages y restricciones de acceso de Java
En Java, las declaraciones de
clases e interfaces se pueden agrupar en packages. El mecanismo de los packages
de Java es similar a los namespaces de C++ (evita colisiones de nombres),
excepto que añade la posibilidad de restriciones de acceso.
Las declaraciones de una
unidad de compilación se añaden a un package si al inicio del texto aparece una
cláusula de la forma:
package id-package ;
En Java:
• Al igual que ocurre en C++
con los namespaces, un package puede estar definido en más de una unidad de
compilación
• Las declaraciones de un
package son por defecto ocultas, es decir, su ámbito es exclusivamente el package
que las declara.
• En un package, las
declaraciones de clases etiquetadas como public son acesibles desde otras unidades
de compilación. Estas clases deben ser declaradas en un archivo que solo las
contenga a ellas.
A modo de ejemplo, veamos un
package Java (P1)
Archivo P1/Privadas.java
package P1 ;
class Privada1
{ public void escribe()
{ System.out.println("clase privada 1") ; }
}
class Privada2
{ public void escribe()
{ System.out.println("clase privada 2") ; }
}
Archivo P1/Publica.java
package P1 ;
public class Publica
{ public void escribe()
{
Privada1 p1 = new Privada1() ;
Privada2 p2 = new Privada2() ;
System.out.println("clase pública:") ;
p1.escribe() ;
p2.escribe() ;
}
}
El package anterior podría
usarse desde una unidad de compilación como esta:
class Main
{
public static void main(
String[] args )
{
P1.Publica p = new
P1.Publica() ;
p.escribe() ;
}
}
La clausula import permite
acortar la notación:
import P1.* ;
class Main2
{
public static void main(
String[] args )
{
Publica p = new Publica() ;
p.escribe() ;
}
}