Fecha y hora actual: Domingo 25 Ago 2019 05:13
Índice del Foro

Foros de programación informática, diseño gráfico y Web

En esta comunidad intentaremos dar soporte de programación a todos los niveles, desde principiantes a profesionales de la informática, desarrollo de programas, programación web y mucho más.

Programando desde 0: 48- Cambio drástico de implementación

Responder al Tema

Índice del Foro > Programación en general > Programando desde 0: 48- Cambio drástico de implementación

Autor Mensaje
Kyshuo Ayame
Moderador Global


Registrado: 07 Ene 2011
Mensajes: 1043

Mensaje Publicado: Miércoles 29 Feb 2012 13:57

Título del mensaje: Programando desde 0: 48- Cambio drástico de implementación

Responder citando

Cambio de implementación en el sistema:

Siguiendo el trabajo con nuestro sistema de ejemplo, veremos el siguiente problema:

La empresa nos dice que han logrado negocios con empresas externas y esto ha causado que su personal deba aumentar considerablemente. Los nuevos negocios llevarán a trabajos zafrales, es decir, habrá períodos con muchas altas de personal y luego períodos con muchas bajas.

El sistema deberá permitir altar a más de 500 personas. Sin embargo, estos nuevos negocios han llevado también a que el sistema de la empresa esté ocupado en otras cuestiones y por tanto no haya suficientes recursos informáticos como para usar memoria estática.

De este modo, se hace necesario que el sistema ocupe la memoria necesaria para mantener a los empleados que están de alta y nada más. Se le explica a la empresa que esto es posible pero que las búsquedas y consultas serán más lentas en el sistema (una mejora lleva a la pérdida de una o más cosas). La empresa acepta esto porque ahora les interesa las altas masivas y las bajas.

De este modo, debemos modificar la implementación de nuestro sistema para que use memoria dinámica y no memoria estática. Entonces ya no podemos usar un arreglo con tope, sino que debemos usar listas encadenadas.

Con esto veremos como la Modularidad nos permite cambiar la implementación de un módulo sin tener que tocar ninguna otra parte del sistema, lo cual es una ventaja enorme. Como usaremos una lista encadenada ya no será posible utilizar el algoritmo de bipartición para las búsquedas de funcionarios, sin embargo mantendremos a la lista ordenada por documento ya que, dentro de todo, las búsquedas son más rápidas en una lista ordenada que en una que no lo está.
La inserción en forma ordenada para una lista encadenada es mucho menos costosa que para un arreglo, ya que lo único que hay que hacer es agregar un nodo entre medio, no hace falta correr todos los demás una posición.

El tipo que teníamos entonces para representar a nuestra ListaPersonas era:

Código:
TYPE
   ListaPersonas= POINTER TO Lista;
   Lista=   RECORD
            personas: ARRAY[1..MAX_PERSONAS] OF Persona;
            tope: [0..MAX_PERSONAS];
         END;


Ahora será así:

Código:
TYPE
   ListaPersonas= POINTER TO NodoLista;
   NodoLista=   RECORD
                  persona: Persona;
                  siguiente: ListaPersonas;
               END;


Como trabajaremos con una lista encadenada no nos interesa tener un máximo número de funcionarios. Podríamos tenerlo si la empresa lo necesitara y entonces deberíamos llevar la cuenta de los nodos en la lista y no dejar agregar más cuando dicho número hubiera alcanzado el máximo. Como no nos interesa llevar dicho cálculo, la operación EsLlenaListaPersonas pierde sentido.

Tenemos aquí entonces que tomar una decisión:

  • Eliminar la operación nos llevará a modificar otros módulos del sistema en donde dicha operación haya sido utilizada.
  • Dejar la operación de modo que siempre devuelva FALSE para no tener que modificar ningún otro módulo del sistema.


Para este caso no es mucho trabajo implementar la primera opción ya que lleva a modificaciones mínimas en el sistema. Sin embargo tomaremos la segunda para mantener una uniformidad en las operaciones de todo el sistema y lograr así que sea posible volver de una implementación a la otra tan solo con cambiar archivo MOD del módulo ListaPersonas. Esto además hace que el archivo de definición siga siendo exactamente el mismo.

Les dejo el nuevo código fuente. Tienen dos opciones:
  • Crean un nuevo archivo de implementación ListaPersonas.mod y simplemente cambiar o sustituir el anterior archivo en la carpeta SRC.
  • Pegan el nuevo código fuente en el archivo ya existente borrando el código anterior.


Eso es decisión suya. Lo que quiero que aprecien, es que a pesar de haber cambiado totalmente la estructura en la que almacenamos a las personas, solo tuvimos que tocar un módulo del sistema (justamente aquel módulo que se encargaba de eso), todo lo demás queda íntegro. Por eso está el tema de medir bien la cohesión y el acoplamiento de los módulos, ya que si ListaPersonas hiciera más tareas que las que corresponden a la única gestión del almacenamiento y borrado de las personas, un cambio como este seguramente tendría un impacto mayor sobre el resto del sistema lo cual acarrearía varios problemas.

Nuevo módulo ListaPersonas:

Código:
IMPLEMENTATION MODULE ListaPersonas;

FROM Persona IMPORT Persona, ObtenerNombrePersona, ObtenerDocumentoPersona,
               ObtenerApellidoPersona, DestruirPersona;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
FROM SWholeIO IMPORT WriteCard;
FROM STextIO IMPORT WriteString, WriteLn;

TYPE
   ListaPersonas= POINTER TO NodoLista;
   NodoLista=   RECORD
                  persona: Persona;
                  siguiente: ListaPersonas;
               END;

(*********************************)
(*         CONSTRUCTORAS         *)
(*********************************)
(*Crea una lista de personas vacía*)
PROCEDURE CrearListaPersonas(): ListaPersonas;
BEGIN
   RETURN NIL;
END CrearListaPersonas;

(*Agrega una persona nueva a la lista de personas en forma ordenada.
PRECONDICIÓN: No debe exitir en la lista otra persona con el mismo documento.*)
PROCEDURE AgregarPersona(p: Persona; VAR l: ListaPersonas);
VAR
   iter1, iter2: ListaPersonas;
   posicionEncontrada: BOOLEAN;
BEGIN
   (*Si la lista está vacía simplemente agregamos la nueva persona a la
   primera   posición*)
   IF EsVaciaListaPersonas(l) THEN
      NEW(l);
      l^.persona:= p;
      l^.siguiente:= NIL;
   ELSE
      (*Deberemos iterar sobre la lista encadenada hasta encontrar la posición
      en la que debe ir asignada*)
      posicionEncontrada:= FALSE;
      
      (*Este bucle itera sobre la lista encadenada hasta encontrar un nodo en
      el cual exista una persona con un documento mayor al de la persona que
      queremos agregar. Esto indica que dicha persona va en ese lugar.
      La variable iter1 apuntará a dicha posición y la variable iter2 apuntará
      a la posición inmediata anterior.*)
      IF (ObtenerDocumentoPersona(l^.persona)>ObtenerDocumentoPersona(p)) THEN
         NEW(iter1);
         iter1^.persona:= p;
         iter1^.siguiente:= l;
         l:= iter1;
      ELSE
         iter1:= l;
         WHILE (iter1<>NIL) AND (NOT posicionEncontrada) DO
            posicionEncontrada:= ObtenerDocumentoPersona(p) <
                     ObtenerDocumentoPersona(iter1^.persona);
            IF NOT posicionEncontrada THEN
               iter2:= iter1;
               iter1:= iter1^.siguiente;
            END;
         END;
         
         IF (posicionEncontrada) THEN
            NEW(iter2^.siguiente);
            iter2:= iter2^.siguiente;
            iter2^.persona:= p;
            iter2^.siguiente:= iter1;
         ELSE
            NEW(iter2^.siguiente);
            iter2:= iter2^.siguiente;
            iter2^.persona:= p;
            iter2^.siguiente:= NIL;
         END;
      END;
   END;
END AgregarPersona;

(*********************************)
(*           PREDICADOS          *)
(*********************************)

(*Devuelve TRUE si existe en la lista una persona con el documento indicado,
FALSE en caso contrario.*)
PROCEDURE ExistePersona(documento: CARDINAL; l: ListaPersonas): BOOLEAN;
VAR   iter: ListaPersonas;
BEGIN
   iter:= l;
   WHILE (NOT EsVaciaListaPersonas(iter)) AND
            (ObtenerDocumentoPersona(iter^.persona)<>documento) DO
         iter:= iter^.siguiente;
   END;
   
   RETURN NOT EsVaciaListaPersonas(iter);
END ExistePersona;

(*Retorna TRUE si la lista de personas es vacía, FALSE en caso contrario*)
PROCEDURE EsVaciaListaPersonas(l: ListaPersonas): BOOLEAN;
BEGIN
   RETURN (l=NIL);
END EsVaciaListaPersonas;

(*Retorna siempre FALSE porque para esta implementación no hay una cantidad
máxima de personas a agregar.*)
PROCEDURE EsLlenaListaPersonas(l: ListaPersonas): BOOLEAN;
BEGIN
   RETURN FALSE;
END EsLlenaListaPersonas;

(*********************************)
(*           SELECTORAS          *)
(*********************************)

(*Devuelve la persona de la lista que tiene el documento indicado.
PRECONDICIÓN: Debe haber en la lista una persona con el documento pasado.*)
PROCEDURE ObtenerPersona(documento: CARDINAL; l: ListaPersonas): Persona;
VAR   iter: ListaPersonas;
BEGIN
   iter:= l;
   WHILE (ObtenerDocumentoPersona(iter^.persona)<>documento) DO
         iter:= iter^.siguiente;
   END;
   RETURN iter^.persona;
END ObtenerPersona;

(*********************************)
(*           INFORMACIÓN         *)
(*********************************)

(*Muestra en pantalla todas las personas existentes en la lista con el siguiente
formato:
   Documento1 Nombre1 Apellido1
   Documento2 Nombre2 Apellido2
   . . .
   DocumentoN NombreN ApellidoN*)
PROCEDURE ListarListaPersonas(l: ListaPersonas);
VAR iter: ListaPersonas;
BEGIN
   iter:= l;
   REPEAT
         WriteCard(ObtenerDocumentoPersona(iter^.persona),1); WriteString(" ");
         WriteString(ObtenerNombrePersona(iter^.persona)); WriteString(" ");
         WriteString(ObtenerApellidoPersona(iter^.persona)); WriteString(" ");
      WriteLn;
         iter:= iter^.siguiente;
   UNTIL (EsVaciaListaPersonas(iter));
END ListarListaPersonas;

(*********************************)
(*          DESTRUCTORAS         *)
(*********************************)

(*Si hay una persona en la lista con el documento indicado esta es eliminada
de la misma. En caso contrario no se realiza acción alguna*)
PROCEDURE EliminarPersona(documento: CARDINAL; VAR l: ListaPersonas);
VAR
   iter, aux: ListaPersonas;
BEGIN
   IF NOT EsVaciaListaPersonas(l) THEN
      iter:= l;

      IF (ObtenerDocumentoPersona(iter^.persona)=documento) THEN
         iter:= l;
         l:= l^.siguiente;
         DestruirPersona(iter^.persona);
         DISPOSE(iter);
      ELSE
          WHILE(ObtenerDocumentoPersona(iter^.siguiente^.persona)<>documento)DO
            iter:= iter^.siguiente;
         END;
         aux:= iter^.siguiente;
         iter^.siguiente:= aux^.siguiente;
         DestruirPersona(aux^.persona);
         DISPOSE(aux);
      END;
   END;
END EliminarPersona;

(*Destruye por completo la lista de personas liberando la memoria ocupada*)
PROCEDURE DestruirListaPersonas(VAR l: ListaPersonas);
VAR
   iter, aux: ListaPersonas;
BEGIN
   iter:= l;
   WHILE (NOT EsVaciaListaPersonas(iter)) DO
         aux:= iter;
         iter:= iter^.siguiente;
         DestruirPersona(aux^.persona);
         DISPOSE(aux);
   END;
END DestruirListaPersonas;
END ListaPersonas.


Las pruebas para este nuevo módulo ListaPersonas son las mismas que ya hicimos. La salvedad es que ahora la salida para la prueba TestListaPersonasStress será otra porque nunca aparecerá el texto “Es llena” ya que esta lista nunca se llena. De este modo, la salida correcta está en el siguiente archivo:

http://netload.in/dateicbpdH1H2NN/TestListaPersonasStress.out.htm

Pueden modificar las pruebas para cargar más de 500 personas en la lista, sin embargo, las que ya existen testean todo lo que hay que testear, de modo que en realidad no hace falta poner a más de 500 personas.

El código no está muy comentado justamente para que ustedes lo analicen y lo estudien. Podría ser más corto, podría usar recursividad... pero eso lo dejaremos para más adelante. El fin de este ejemplo era justamente mostrarles como incentivo un ejemplo en el que un gran cambio tiene un impacto muy bajo a nivel del sistema en general.
Seguiremos entonces con Tipos Abstractos de Datos, comenzando a ver algunos con nombre y apellido ya que son los más conocidos y habitualmente usados, pero lo dejaremos para la próxima.

Saludos.



Ultima edición por Kyshuo Ayame el Martes 18 Sep 2012 21:08; editado 2 veces
Volver arriba
Ver perfil del usuario Enviar mensaje privado
ale91
Usuario Iniciado


Registrado: 13 Abr 2012
Mensajes: 18

Mensaje Publicado: Martes 17 Abr 2012 23:52

Título del mensaje: Re: Programando desde 0: 48- Cambio drástico de implementaci

Responder citando

Muy buen ejemplo, hice este proyecto aunque el Modulo Principal copie bastante por que era muy complicado.
Que la forma de Agregar una Persona sea en forma ordenada simplifica mucho las cosas, otros ejemplos piden agregar al final y luego en otro procedimiento ordenar la lista

Volver arriba
Ver perfil del usuario Enviar mensaje privado
sr floyd
Usuario Activo


Registrado: 05 Sep 2011
Mensajes: 196

Mensaje Publicado: Miércoles 30 Oct 2013 00:11

Título del mensaje: Re: Programando desde 0: 48- Cambio drástico de implementaci

Responder citando

Estimado Kyshuo el enlace al final de la lección está roto Ojos

Volver arriba
Ver perfil del usuario Enviar mensaje privado MSN Messenger
Responder al Tema
Mostrar mensajes anteriores:   
Ir a:  
Todas las horas están en GMT + 2 Horas

Temas relacionados

Tema Autor Foros Respuestas Publicado
El foro no contiene ningún mensaje nuevo

Buenas desde el sur del sur =)

Maugarni Preséntate a la comunidad 1 Jueves 22 Ago 2019 14:09 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Hola desde bcn

Dav2k6 Preséntate a la comunidad 2 Miércoles 26 Jun 2019 19:22 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Existen problemas al descargar musica desde you...

SusanaP Tu PC 2 Martes 26 Mar 2019 19:22 Ver último mensaje
El foro no contiene ningún mensaje nuevo

hola!! los saludo desde argentina

mery Preséntate a la comunidad 2 Jueves 13 Dic 2018 17:28 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Llamada a web service desde form

mrrobot2 Programación Web en general 1 Martes 14 Nov 2017 00:50 Ver último mensaje
Panel de Control
No puede crear mensajes, No puede responder temas, No puede editar sus mensajes, No puede borrar sus mensajes, No puede votar en encuestas,