0% encontró este documento útil (0 votos)
17 vistas20 páginas

Simulaciones con PSOO en POO

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
17 vistas20 páginas

Simulaciones con PSOO en POO

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

GUIA DE REFERENCIA RAPIDA DE PSOO - 1999

Una visión práctica

INTRODUCCION
* PSOO (Paquete de Simulación Orientada a Objetos)
A lo largo de estas páginas se describirá brevemente un software capaz de permitir realizar simulaciones
en Turbo Pascal V6.0 y en Borland C++ V3.1 (que aún se encuentra en etapa experimental). Es importante
destacar que las mismas se llevan a cabo utilizando el enfoque orientado a objetos, el cual demostró a lo largo de
los años ser uno de los más recomendados para muchos casos de simulación por computadora.

* Pero, ¿qué herramientas ofrece PSOO?


El principal elemento, como ya se mencionó, es la posibilidad de programar el modelo utilizando objetos.
El lector podrá apreciar cómo, utilizando este modo de simulación, se facilita la tarea que implica programar una
computadora para que se comporte lo más aproximadamente posible a la realidad que se desea estudiar.

Además cuenta con un manejador de semáforos que permite coordinar las tareas que desarrollan los
objetos durante la simulación, evitando de esta manera posibles interferencias. Tal herramienta es muy útil, pues
no debemos olvidar que en esta filosofía los objetos que participan en la simulación actúan concurrentemente, por
lo que es imperioso sincronizar sus actividades. (En el presente resumen no analizaremos los semáforos).

Teniendo en cuenta que en muchos de los casos de simulación se necesitan estructuras tales como colas,
conjuntos, etc., PSOO provee un módulo que posee manipuladores que permiten agrupar datos bajo esas formas.

Tampoco debemos olvidar que la toma de estadísticas cumple aquí un papel muy importante. De allí que
estudiaremos la manera de tomarlas mediante este soft; al respecto se recomendarán distintas técnicas
mencionando sus pro y sus contras e indicando en qué casos conviene utilizar una u otra.

Como herramienta adicional, ofrece al programador un módulo que le permitirá contar con diversos
generadores de distribuciones los cuales serán de mucha utilidad para simular situaciones estocásticas.

Pág. 1 de 20
CLASES. OBJETOS. SIMULACION.
La POO tiene una gran aplicabilidad en la simulación de eventos discretos. Se usa también con gran éxito
en inteligencia artificial. Es importante destacar que la programación orientada a objetos es uno de los tantos
enfoques que existen (tenemos otros como el imperativo, funcional, lógico, etc).

Para entender los objetos primeramente se debe manejar la idea de clase. Es útil pensar que lo que se está
manejando es un concepto y por lo tanto la clase, como tal, debe tener todos los elementos necesarios para definir
completamente ese concepto. Así, por ejemplo, los aeroplanos se pueden describir en términos físicos (el número
de pasajeros que pueden llevar, el empuje que desarrollan, su coeficiente de resistencia al avance, etc). Como
alternativa, un aeroplano se puede describir en términos funcionales (despega, desciende y asciende, gira y
aterriza, etc). Ni la descripción física ni la funcional, por separado, captan la esencia de lo que es un aeroplano. En
realidad, para que la definición esté completa se necesita tener en cuenta ambas descripciones.
Vemos que para definir un concepto se necesita además de la estructura de datos que responda a ese
concepto, las funciones y operaciones que involucra. De esta manera la idea de una cola queda definida como una
sucesión de elementos (arreglo de elementos por ejemplo) y las operaciones tales como poner y sacar esos
elementos.

Se puede decir entonces que:


CLASE = DATOS + OPERACIONES o MENSAJES (definidos sobre esos datos)

* OBJETOS:

En este estilo se dice que un dato es un objeto de algún tipo abstracto de dato o clase. Podemos ver que
un objeto es una instancia de una clase dada. Por ejemplo, un BOING 707 es un objeto de la clase aeroplano y
heredará todos los datos y acciones que los aeroplanos pueden tener.

* CLASES Y OBJETOS. CUALIDADES:

- Un objeto de una clase sólo puede hacer lo que la clase le permite. Si cambiamos la clase de ese objeto
por otra que posee las mismas operaciones pero implementadas de forma diferente, el programa que usaba ese
objeto tendrá el mismo comportamiento funcional.

- Se puede comprender el programa sin requerir información de la implementación de las rutinas de la


clase. (principio de la modularidad).

- Una misma clase se puede utilizar en distintos programas (biblioteca de tipos abstractos de datos).

- Un objeto no puede acceder directamente a los datos de otro, sino en forma indirecta, usando las
operaciones permitidas por éste (principio del ocultamiento de la información).

- Puede haber especializaciones o subclases de una clase dada. Ejemplo:


Se puede decir que la clase animales vertebrados y animales invertebrados son subclases especializadas
de una mayor, o metaclase denominada clase animal.

- Los mensajes pueden tener como argumentos a otros objetos. En este caso el objeto que envía el

Pág. 2 de 20
mensaje se denomina emisor y el que lo recibe se llama receptor. Es claro que este último debe poseer en su
"repertorio" de operaciones el mensaje en cuestión para que la transmisión sea legal. Ejemplo:
Cuando un cliente hace una compra, necesita preguntar al vendedor el precio del artículo que le interesa.
El cliente es el emisor del mensaje ¿cuanto sale este artículo? y el vendedor cumple el rol de receptor.

- Los mensajes pueden contestar algún valor de la estructura de datos del objeto o pueden cambiar sus
valores. En el ejemplo anterior, el vendedor ante el mensaje CuantoCuesta(vendedor,artículo) se limita a
contestar un valor de su estructura de datos: el precio del artículo solicitado.

- Pueden existir métodos (mensajes) con el mismo nombre pero de clases distintas.

* LOS OBJETOS EN LA SIMULACION:

¿Cómo podemos aplicar estas ideas a las tareas de simulación?


Podemos decir que la simulación permite estudiar un cierto sistema del mundo real. Pensemos que cada
entidad de ese sistema es un objeto (el cliente de un supermercado, el cajero de un banco, una cierta máquina,
etc).
De esta, manera las imágenes simbólicas de las cosas del mundo real se conciben como objetos, y sus
interrelaciones como mensajes que se envían unos a otros. El modelo de ese sistema es una red de objetos
interrelacionados a través de dichos mensajes.

Si observamos detenidamente las entidades que aparecen en los sistemas, notaremos que podemos
representarla con dos tipos básicos de objetos: los activos y los pasivos.

Los objetos activos tienen lo que se llama un ciclo de vida, es decir un programa que les permiten
realizar tareas propias de su naturaleza. Tomemos por ejemplo una persona que quiere realizar un trámite. En este
Pág. 3 de 20
caso la persona es el objeto que realiza la tarea representada por el trámite en cuestión.

Los pasivos no tienen un ciclo de vida. Sólo poseen un conjunto de operaciones definidas sobre sus
estructuras. Este es el caso de los objetos colas, conjuntos, etc., que lo único que saben y pueden hacer, entre otras
cosas, es incorporar o sacar elementos de sus estructuras a pedido de otros objetos que pueden a su vez ser activos
o pasivos.

Podríamos pensar los objetos activos como "actores" que aparecen y desaparecen de la simulación a
medida que el tiempo pasa. Inclusive pueden detener sus actividades hasta que otros objetos les ordenen continuar
o hasta que un cierto tiempo haya pasado. Es importante destacar que las simulaciones que se realicen con PSOO
estarán regidas por eventos discretos, es decir que no habrá actividad continua en el tiempo por parte de ningún
objeto, por lo que éstos pueden quedar congelados esperando que suceda un evento que los reanime.

Si alguna vez tuvo la oportunidad de presenciar una obra de teatro, se habrá percatado que los actores
trabajan al mismo tiempo sobre el escenario. Eso mismo ocurre en una simulación con los objetos.

Es así que PSOO incorpora herramientas que le permite "simular" la multitarea. Dichas herramientas se
construyeron sobre la base de una idea: las corrutinas.

Podemos pensarlas como procesos que tienen la capacidad de suspender sus tareas y, en otro momento,
reanudarlas a pedido de otros procesos que siguen activos.

PSOO aplica este concepto a los ciclos de vida, logrando emular el trabajo concurrente de los objetos.

Quizás Ud. se estará preguntando ¿cómo se implementa corrutinas en TP6 y en C++?. La respuesta no la
encontrará en este trabajo. Invito al lector interesado en el tema consultar la sección VIII (PARTE II) del "Manual
de PSOO" (versión TP6).

De lo que llevamos expuesto podemos pensar que un objeto activo, en su ciclo de vida, puede decidir:

- Crear un nuevo objeto: suspender su ciclo de vida y continuarlo después de que el nuevo objeto decida
devolverle el control. Quizás el lector se pregunte porqué el nuevo objeto se comporta tan "caprichosamente" con
su creador pero hay una razón muy fuerte para esto: la simulación no puede seguir hasta que el nuevo objeto no
"pise firme" el escenario de la simulación. Si no fuese así imagine lo que ocurriría si un objeto emite un mensaje a
otro que justo está "naciendo" en ese momento , ¡un desastre!.

- Suspenderse: dejar de hacer la tarea que estaba haciendo hasta que otro objeto lo active o reanude.

- Activar a un objeto que se encuentra suspendido o esperando. El efecto que causa esta orden es la
"reanimación" del ciclo de vida del otro objeto al mismo tiempo que continúa realizando las tareas que se
detallan después de la orden activar.
- Reanudar a un objeto que se encuentra suspendido o esperando. Se anima al objeto suspendido a continuar con
sus tareas pero el objeto emisor de esta orden queda suspendido.

- Esperar un cierto tiempo para continuar con sus tareas. Es posible que la espera se rompa antes de lo
programado si otro objeto hace un activar o un reanudar.

- Borrarse de la simulación: al concluir su ciclo de vida el objeto se "autodestruye".


Pág. 4 de 20
- Terminar la actuación en la simulación: el ciclo de vida concluye pero el objeto no se retira de la simulación.
Sobreviven sus datos y mensajes para consultar esos datos. Para "borrarlo" efectivamente, otro objeto activo
deberá enviarle el mensaje borrar(obj).

**** ¿Cómo podríamos denotar sintácticamente esas órdenes? De esta forma:


 Crear un nuevo objeto. ─── nuevo(obj,argumentos)
 Suspender su ciclo de vida. ─── suspenderse
 Reanudar a otro obj. y conti- ─── activar(obj)
nuar con sus tareas normalmente.
 Reanudar a otro obj. suspen- ─── reanudar(obj)
diendo sus tareas.
 Retardar sus operaciones un ─── esperar(tiempo)1
cierto tiempo.
 "Borrarse" de la simulación. ─── borrarse
 "Terminar" el ciclo de vida ─── terminar
sin borrarse de la simulación.

Con el propósito de afianzar los conceptos vertidos, a continuación desarrollaremos algunos ejemplos
usando para ello una sintaxis natural. Aun cuando la sintaxis natural puede explicarse por sí misma, es
conveniente destacar que:

- Permitiremos que el significado de un símbolo quede determinado por el contexto, posibilitando de esta
manera el uso de un mismo nombre para una clase y un objeto perteneciente a esa clase (es muy difícil que un
compilador acepte este tipo de cosas).

- Los mensajes deberán contener los tres elementos básicos:


(1) el tipo de mensaje,
(2) el objeto receptor y
(3) la lista de argumentos.

*** Nosotros adoptaremos la forma:

tipo de mensaje(Obj. RECEPTOR, lista de argumentos)

- Cuando se crea un objeto de una clase, se necesitan valores iniciales para cargar su estructura de datos.
A cada uno de éstos los denotaremos con la frase "argumento de creación". Al crear un nuevo objeto se proveerá
esa información a través de una lista de argumentos.
- Y en general, cualquier cosa que se sobreentienda se omitirá (declaraciones de variables simples,
iniciación de índices, etc). Recordemos lo que dice el dicho: "A buen entendedor, pocas palabras".

EJEMPLO 1: sistema con una sola estación.


Se trata de obtener por simulación el tiempo promedio en el sistema de un modelo de cola simple con

1
Esperar se comporta como una función lógica que devuelve verdad cuando la espera se completa, y falso cuando es interrumpida.

Pág. 5 de 20
servicios y llegadas exponenciales.

Para ello detectaremos las entidades que se observan en el sistema y luego derivaremos los objetos que
participarán en la simulación:

NOMBRE DE LA NOMBRE DEL OBJETO


ENTIDAD

Cajero de la estación cajero


clientes cliente
-------- director
-------- observador

CLASE CLIENTE:
Datos:
tSer:tiempo "arg. de creación"
HoraLlegada:tiempo
Mensajes:
tSer:retornar(tSer)
Ciclo de vida:
esperar(dExp(λ))
nuevo cliente(dExp(µ))
HoraLlegada=HoraAct

Llegue(cajero, yo) //esto me detiene hasta que el cajero se desocupa


esperar(tSer) //tomo mi servicio
MeVoy(cajero, yo) //aviso al cajero que me voy para que el siga atendiendo a los que esperan
registrar(observador,Hora - HoraLlegada)
borrarse

CLASE CAJERO:
Datos:
ColaFIFO llamada cola //se inicia cuando se crea el objeto de tipo cajero
Mensajes: ---
Llegue(cliente):
si no vacia(cola) 
poner(cola, cliente)
Suspenderse //se congela la ejecución del cliente porque tiene que hacer cola
sino
poner(cola, cliente)
MeVoy(cliente):

Pág. 6 de 20
sacar(cola) //note que sacar siempre saca al primero, por lo que no es necesario indicar
a cuál cliente extraer (el parámetro cliente queda inutilizado. Sólo se lo
pone por claridad)
si no vacia(cola) 
activar(primero(cola))

Ciclo de vida: ---


CLASE DIRECTOR:
Datos:
TiempoSimulación:tiempo "arg. de creación"
Mensajes: ---
Ciclo de vida:
observador=nuevo(observador,"Tiempo promedio en el sistema:")
nuevo cajero
nuevo cliente(dExp(µ))
esperar(TiempoSimulación)
ImprimirEstadísticas(observador)
borrarse
CLASE OBSERVADOR:
Datos:
Mensaje:cadena de car. "arg. de creación"
total:número
NumElementos:número
Mensajes:
Iniciar(frase):
mensaje=frase
total=0
NumElementos=0
Registrar(dato):
total=total + dato
NumElementos=NumElementos + 1
ImprimirEstadísticas:
imprimir: mensaje + total/NumElementos

¿Qué es el objeto director?: es un objeto obligatorio en toda simulación, pues es el encargado de poner
en movimiento los objetos, de iniciar las estadísticas y, al expirar el tiempo de simulación, mostrar los resultados
finales. Se lo considera un objeto activo y su ciclo de vida es el primero que debe ejecutarse.

¿Qué es el objeto observador?: es un recolector de estadísticas. En nuestro caso lo único que hace es
acumular los tiempos en el sistema de cada cliente y contar los que salen. Con esa información podrá calcular el
tiempo promedio en el sistema. Por mayores detalles de posibles técnicas para tomar estadísticas, consulte el
apartado "TOMA DE ESTADISTICAS"

EJEMPLO 2: sistema con una estación y atención del trabajo más corto.

El sistema es similar al visto anteriormente, pero con la salvedad de que ahora no se atiende por orden de
llegada sino que se prioriza al del trabajo más corto. Después que el cajero termina de atender a un cliente, elige
de la cola al que tiene menor tiempo de servicio.

Pág. 7 de 20
Para este sistema no nos sirve una cola FIFO, sino una estructura capaz de entregar el menor elemento de
acuerdo con un parámetro. En nuestro caso ese parámetro será el tiempo de servicio.

A primera vista, podríamos pensar que lo que estamos buscando no es más que una simple lista ordenada
según ese parámetro. Es muy fácil de programar y nos devolvería sin ningún problema el elemento menor. Pero
¡no nos apresuremos en decidirnos por ella!; hemos dejado de lado en este razonamiento una característica muy
particular de nuestro problema: lo único que queremos es simplemente el elemento menor. Teniendo en cuenta
esto, se puede pensar en otra estructura que haga lo mismo sin mantener un orden completo. Si bien esta
alternativa es más costosa en lo que se refiere a programación, es significativamente económica en cuanto a
tiempo de ejecución, factor que debe tenerse muy en cuenta en toda simulación.

Una estructura con este comportamiento recibe el nombre de HEAP y su interface de mensajes
(pensándola como un objeto) es como sigue:

- poner(HEAP,Obj,prm) ─── pone un obj. en el HEAP y le asigna una prioridad según el parámetro
prm (numérico). Un obj. con menor "prm" tendrá la mayor prioridad.
- primero(HEAP) ─── devuelve el obj. de menor prioridad del HEAP
- sacar(HEAP) ─── saca el obj. de menor prioridad del HEAP
- Vacia(HEAP) ─── devuelve verdad si el HEAP está vacío y falso si no es así
- Iniciar(HEAP) ─── arranca el obj. HEAP poniéndolo vacío

Consideremos los siguientes puntos:

(1) La interface de mensajes del HEAP es muy similar a la de la clase cola FIFO o LIFO. Esto no nos debe
sorprender pues la clase HEAP es una cola de prioridad como cualquier otra (FIFO, LIFO, etc) y las operaciones
que se realizan sobre ellas son homólogas.
(2) Si estudiamos detenidamente el pseudocódigo del ejercicio anterior, veremos que el único motivo por el cual
la gente es atendida por orden de llegada, es porque el obj. cola fue definido como perteneciente a la clase cola
FIFO (ver tabla).

De (1) y (2) podemos concluir que con sólo cambiar el tipo del obj. cola del modelo anterior tenemos
automáticamente el pseudocódigo de este nuevo caso.
Quizás hechos como éstos hicieron pensar que los objetos serían buenos aliados en la simulación.

EJEMPLO 3: sistema con dos estaciones

Si Ud. lee con atención los pseudocódigos de los clientes y del cajero, notará que lo único que tuvimos
que hacer para confeccionarlos fue imaginarnos qué es lo que hace un cliente al llegar al sistema. Lo mismo
sucedió con el cajero. El problema se redujo a "contarle" a la computadora qué es lo que hacen las entidades en el
mundo real.
El pseudocódigo se parece a un "guión" que deberán seguir los actores durante la simulación.
Lógicamente, el éxito de la obra (simulación) dependerá de los guiones que se hayan elaborado. Recuerde que hay
muchas formas de contar una cosa, pero sólo unas pocas agradan al público.

Pág. 8 de 20
TOMA DE ESTADISTICAS
Cada vez que realizamos una simulación procuramos obtener información que luego proyectamos hacia
el sistema real en estudio. Pero para poder obtenerla debemos recoger ciertas estadísticas durante la ejecución.

La gente que trabaja en simulación conoce la importancia de realizar el algoritmo separando el modelo de
la toma de estadística.

Cuando trabajamos con objetos, esa meta se hace un tanto difícil de alcanzar en su totalidad. Usted puede
darse cuenta de esto revisando los ejemplos que vimos anteriormente.

Casi siempre nos vemos obligados a recopilar información estadística en los ciclos de vida. Esto no nos
debe extrañar, ya que un ciclo de vida indica las actividades que desarrolla el objeto; una de ellas es tomar las
estadísticas que se refieren a él. Por ejemplo, sería interesante calcular el tiempo promedio en el sistema de los
clientes que acuden a un local a realizar algún trámite. En ese caso, cada cliente tiene el deber de sumar en un
acumulador el tiempo de su estadía total en el sistema, y de incrementar un contador cuando se retira del negocio.
Con estas dos informaciones globales podemos calcular fácilmente lo que buscamos.

A continuación desarrollaremos algunas formas de tomar estos datos:

* El objeto se encarga de recolectar la información en variables globales.


Este es el método que vimos anteriormente.
 Ventajas: - es simple de aplicar.
- es rápido, pues los objetos pueden acceder directamente a los acumuladores y contadores.
 Desventajas: - mezcla la toma de estadísticas con el modelo.
- usa variables globales para la toma de estadísticas, con lo que se corre el riesgo de
alterarlas accidentalmente desde otro punto del programa.

* El objeto se encarga de recolectar la información en variables globales, particionando su ciclo de vida.


La idea clave es particionar el ciclo de vida en etapas. Por ejemplo: el cliente llega, comienza a ser
atendido, se retira. Un esquema del pseudocódigo de este objeto sería:
CLIENTE:
Datos:
~~~~~~
~~~~~~
Mensajes:
LlegaCola:
~~~~~~
~~~~~~
~~~~~~
ComienzaAtención:
~~~~~~
~~~~~~
~~~~~~
SeRetira:
~~~~~~
~~~~~~
~~~~~~

Pág. 9 de 20
CicloDeVida:
LlegaCola
ComienzaAtención
SeRetira
Borrarse

Como verá, no hay ningún indicio de la toma de estadísticas. Cuando esto se quiera realizar, bastará
agregar la subclase siguiente:
EstdCliente subclase de cliente
Datos:
~~~~~~
~~~~~~
Mensajes:
LlegaCola:
~~~~~~
~~~~~~
LlegaCola [de superclase]
~~~~~~
~~~~~~
ComienzaAtención:
~~~~~~
~~~~~~
ComienzaAtención [de superclase]
~~~~~~
~~~~~~
SeRetira:
~~~~~~
~~~~~~
SeRetira [de superclase]
~~~~~~
~~~~~~

Los objetos clientes en la simulación no pertenecerán a la clase cliente sino a la subclase EstdCliente
(estadística de cliente). Los datos recogidos se guardan en variables globales.

Imaginemos que deseamos calcular el tiempo promedio en el sistema por cliente, y el tiempo promedio de
espera en la cola hasta que comienza su atención.

Definiremos una subclase adecuada de EstdCliente:


EstdCliente subclase de cliente
Datos:
HoraLlegada:tiempo
HoraComAtencion:tiempo
Mensajes:
LlegaCola:
LlegaCola [de superclase]
HoraLlegada=HoraActual
ComienzaAtención:
HoraComAtención=HoraActual
ComienzaAtención [de superclase]
Pág. 10 de 20
SeRetira:
SeRetira [de superclase]
tts=tts + HorActual - HoraLlegada
tte=tte + HraComAtención + HoraLlegada
tgs=tgs + 1

Se sugiere que la fragmentación del ciclo de vida se haga sólo en tantas etapas como sean necesarias para
tomar los datos que interesan sobre ese objeto.

 Ventajas: - el modelo no se mezcla con la toma de estadísticas.


- la recolección de datos es clara.
 Desventajas: - un tanto lenta para las llamadas de los mensajes en los ciclos de vida.
- se puede llegar a fragmentar demasiado el ciclo de vida.

* Las estadísticas las toma un objeto especialmente diseñado para ello: el observador.

Los objetos "avisan" al observador sobre ciertos acontecimientos (llegué, salí, me atienden), y este
registra la información en sus propias estructuras de datos (ya no se usan variables globales para este fin). Los
ejemplos vistos fueron realizados con este principio.

Para el caso que vimos en el método anterior, podríamos definir el siguiente observador:
Observador:
Datos:
tts: tiempo
tte: tiempo
tgs: número
Mensajes:
ComAten(TiempoEspera: tiempo)
tte=tte + TiempoEspera
MeRetiro(HoraLlegada: tiempo)
tts=tts + HoraActual - HoraLlegada
tgs=tgs + 1

Por otro lado, en el ciclo de vida del cliente estarán colocados estratégicamente estos mensajes hacia el
observador. Note que el cliente debe almacenar la hora de llegada al sistema, puesto que el mensaje MeRetiro
requiere este dato como parámetro.

En el ciclo de vida del director se deberá incluir la iniciación del observador como así también, al
finalizar la simulación, llamar al método que muestra los resultados estadísticos.

 Ventajas: - el modelo y la toma de estadísticas no se mezcla demasiado.


- no se usan variables globales de recolección de datos, en vez de ello se tiene un objeto que ejerce
total control sobre esta información.
- el reporte y la iniciación de las variables quedan a cargo de ese único objeto. Esto contribuye a la
claridad del programa.
 Desventajas: - puede resultar un tanto lento por las reiteradas llamadas a los métodos del observador.
- el objeto que está sujeto a estadísticas debe conservar cierta información para pasársela al

Pág. 11 de 20
observador en los momentos oportunos (por ejemplo la hora de llegada).

* Los observadores múltiples:


Examinemos la siguiente clase de observador:

ObsPromedio:
Datos:
acum: número
cont: número
mensaje: cadena de caracteres

Mensajes:
Iniciar(título: cadena de caracteres)
mensaje=título
acum=0
cont=0
Acumulador(dato: entero):
acum=acum + dato
cont=cont + 1
MostrarEstad:
imprimir(Mensaje, acum/cont)

Como habrá notado, se trata de un observador que devuelve el promedio de algo. El mensaje que
acompaña al promedio y denota su naturaleza se lo especifica en su iniciación.

Se pueden crear muchos objetos de esta clase para que calculen diferentes promedios. Para el ejemplo del
punto anterior podemos definir los observadores:

ObsTiempoSist y ObsTiempoEsp

Ambos pertenecen a la clase ObsPromedio y pueden utilizarse para tomar las estadísticas que
deseábamos.

No olvidemos iniciarlos en el director con los mensajes correspondientes, como así también ordenarles, al
finalizar la simulación, que muestren los resultados.

No es obligatorio que el observador únicamente sepa calcular promedios, podemos agregarle la obtención
de la varianza, desvíos, etc. Inclusive si es conveniente, se pueden definir diferentes clases de observadores que
calculen por separado esos valores.

Las ventajas y desventajas son las mismas de los métodos anteriores, pero se le agrega la ventaja de
quedar en condiciones para formar una biblioteca de clases de observadores que puedan usarse en diferentes casos
de simulación. La desventaja estaría dada por la aparición de numerosos objetos para manejar, aunque esto no nos
debe preocupar demasiado. Sólo se debe tener cuidado de no olvidar iniciarlos en el director.

Al respecto, PSOO cuenta con la unidad de "MONITOREO" que colecciona tres clases tomadoras de
estadísticas.
- Un observador de promedios.
- Un observador de desvíos y varianzas.
Pág. 12 de 20
- Un observador de promedios, desvíos y varianzas.
Ver el apartado siguiente para mayores detalles.
* Observadores y ciclos de vida divididos en etapas
Es la mezcla de las dos ideas vistas, con las ventajas y desventajas de una y de otra.

No es muy recomendable, puesto que las llamadas a los métodos de las etapas y de los observadores
comienzan a hacer sentir mucho sus efectos sobre el tiempo de ejecución del programa. Quizás lo más
conveniente sea el uso de la técnica de los objetos múltiples, aunque deberá tenerse en cuenta que esto depende en
gran medida de lo que se está simulando y de cómo se lo está haciendo.

** No crea que los métodos mencionados son los únicos y que cualquier otro podría ser malo. En realidad
debemos encontrar la técnica de recolección de datos que más "encaje" con lo que estamos simulando. Para ello
hemos de tener en cuenta aspectos de claridad, velocidad, memoria requerida, reusabilidad, etc., y buscar aquella
técnica que mejor equilibre esos aspectos.

Pág. 13 de 20
UNIDADES CONSTITUTIVAS DE PSOO (TP6)
A continuación se ofrece un resumen de las unidades que componen PSOO. Dicho resumen NO intenta
ser una explicación de cómo funcionan las mismas, sino ofrecer la información necesaria para poder utilizar
este paquete en una simulación orientada a objetos. (Ver además los fuentes de los ejemplos que se adjuntan a
este resumen).

Notará el lector que aparece una unidad que no se utilizará directamente en ninguna simulación que
realicemos. Esta es la unidad de gestión dinámica especializada (Gest_Din). Su misión es la de interceptar al
manejador dinámico de Pascal para tomar el control de la gestión de la memoria. En este caso se la usa para
acelerar el trabajo de la unidad de corrutinas. Además intercepta al manejador de errores del HEAP de TP6 para
generar errores más "amigables" en los que incluso se informa las posibles causas que lo provocaron. Una
información más detallada la encontrará en el propio fuente de esta unidad (comentarios realizados en la sección
de interface).
A fin de agilizar la tarea del programación se describen a continuación las interfaces de los distintos
módulos.

** GESTOR DINAMICO (GestDin):


procedimientos:
IniciarGestorDinamico(TamDin:word;FactorAumento:real);
ObtenerMemoria(i:word; var p:pointer);
LiberarMemoria(i:word; p:pointer);
function ErrorMemoLlena(tam:word):integer;

** CORRUTINAS (Corrut):
Variables:
BasePila:word; base del stack a partir de la cual se
almacena la pila
TamMinBuffDin:word; tamaño del vector del gestor dinámico
especializado
Procedimentos:
IniciarCorrutinas(Pila,TamDin:word;FactorAumento:real); inicia el gestor de corrutinas
function SetJmp (var p:pointer):integer; guarda el contenido de la pila
function LongJmp(var p:pointer; i:integer):integer; restaura su contenido

** ESTRUCTURAS DE DATOS (Estr_Dat):


Constantes:
MedidaHeap =1000; máxima cantidad de elementos que puede manejar el heap.

Tipos:
PtrColaFifo =^ObjFifo; punt. cola FIFO.
PtrColaLifo =^ObjLifo; punt. cola LIFO.

TipoNodoHeap=record formato del reg. del nodo del HEAP


obj:pointer;
tiempo:real;
end;

Pág. 14 de 20
Definición de clases:
ObjLifo: Clase dotada para el manejo de una pila de objetos (pila de punteros).
constructor iniciar(TamMinCola:word;FactorAmpl:real);
constructor inic;
procedure poner(Obj:pointer);
function sacar:pointer;
function primero:pointer;
function vacia :boolean;
destructor borrar;

ObjFifo:sub(ObjLifo) Subclase de cola (cola LIFO).


Contiene la estructura y los mensajes necesarios para el manejo de una cola FIFO.
constructor iniciar(TamMinCola:word;FactorAmpl:real);
constructor inic;
function sacar:pointer;
function primero:pointer;

ObjConj:Sub(ObjLifo) Objeto CONJUNTO que coloca elementos en una cola LIFO heredada.
procedure sacar(obj:pointer);
function SacarUltimo:pointer;
function pertenece(obj:pointer):boolean;
function vacio :boolean;

ObjHeap=object Objeto HEAP contiene los mensajes y estructuras necesarias para el manejo de un
heap. Tiene incorporado además un mensaje de visualización que permite presentar
por pantalla el árbol del heap.
constructor Iniciar;
procedure poner(r:real;datos:pointer);
procedure sacar(var r:real;var datos:pointer);
function vacio:Boolean;
function AlturaHeap(raiz:integer):integer;
procedure ImpArbol(raiz,x,y:integer);

** SIMULACION (simulaci):
Tipos:
PtrObjSim=^ObjSim; puntero a un objeto de simulación

Definición de clases:
ObjSim=object Objeto de simulación. Todos los objetos no pasivos de la simulación deben
declararse como estáticos.
constructor iniciar;
procedure CicloDeVida; virtual;
destructor borrar; virtual;

----------- PROCEDIMIENTOS DEL "DESPACHADOR" --------------


Pág. 15 de 20
procedure IniciarSim(direc:PtrObjSim); inicializa la simulación
procedure nuevo(NuevoObj:PtrObjSim); da el control a nuevo obj.
procedure activar(NuevoObjActivo:PtrObjSim); activa un objeto existente
procedure esperar(tEsp:real); retardo de tEsp para seguir
procedure suspenderse; suspender acción del obj.
procedure reanudar(pObj:PtrObjSim); reanuda un determinado obj.
procedure borrarse; salir de la simulación
procedure terminar; salir de la simulación sin borrar las estructuras de datos

-------- VARIABLES COMPARTIDAS POR EL "DESPACHADOR" --------

Variables:
HoraAct:real; hora actual en el sistema
mismo:pointer; puntero al objeto corriente
yo:pointer absolute mismo; réplica de "mismo".
Hora:real absolute HoraAct; réplica de HoraAct.
HoraActual:real absolute HoraAct; réplica de HoraAct.

Las siguientes variables toman valores por defecto adecuados para una simulación de mediana envergadura:

TamMinColaAct :word; tamaño mínimo de la pila de obj. activos


FacAmplColaAct:real; factor de ampliación de su vector dinámico
TamMinConjSusp:word; tamaño mínimo del conj. de obj. suspendidos
FacAmplConjSusp:real; factor de ampliación de su vector dinámico
TamMinBuffCorr:word; tamaño mínimo del vector del gestor dinámico especializado.
FacAmplGestDin:real; factor de ampliación del vector del gestor dinámico especializado.

** SEMAFOROS (semaforo):
Declaración de clases:
ObjSmf: clase que ofrece los mecanismos de un semáforo de prioridad FIFO.
procedure iniciar(TamMinColaEsp:word);
procedure esperar(Obj:pointer);
procedure continuar;
procedure borrar;

** GENERADOR DE DISTRIBUCIONES (Distribu):


Funciones:
function dExp(tasa:real):real;
function dNorm(media,desvio:real):real;
function dUnif(a,b:real):real;
function dEntera(a,b:integer):integer;

** MONITOREO DE LA SIMULACION (monitor):


Tipos:
Pág. 16 de 20
letrero=string[60];

Definición de clases:
ObsPromedio:
procedure iniciar(titulo:letrero); título que aparece al lado del promedio
procedure acumular(dato:real); incorporar dato al promedio
procedure MostrarEstd; mostrar promedio
ObsDesvio:
procedure iniciar(titulo1,titulo2:letrero); título1 aparece al lado del desvío y título2 al lado de la varianza.
procedure acumular(dato:real); incorporar dato al cálculo de la varianza y el desvío
procedure MostrarEstd; mostrar varianza y desvío

ObsDatos:
procedure iniciar(titulo1,titulo2,titulo3:letrero);
título1 -> desvío
título2 -> varianza
título3 -> promedio
procedure acumular(dato:real); incorporar dato al cálculo del desvío, varianza y promedio
procedure MostrarEstd; mostrar desvío, varianza y promedio

Como notará el lector hay varias unidades que pueden ser muy útiles para otras aplicaciones, ese fue el
espíritu que se siguió durante la construcción de PSOO: "modularizarlo de tal forma que varias partes puedan
utilizarse en otros programas que incluso no tengan nada que ver con simulaciones". Para mayores detalles
acerca de este paquete dirigirse al "Manual de PSOO" (Versión TP6).

Pág. 17 de 20
UNIDADES CONSTITUTIVAS DE PSOO (C++)
A continuación se ofrece un resumen de las unidades que componen PSOO para C++. Dicho resumen
NO intenta ser una explicación de cómo funcionan las mismas, sino ofrecer la información necesaria para poder
utilizar este paquete en una simulación orientada a objetos. (Ver además los fuentes de los ejemplos que se
adjuntan a este resumen).

A fin de agilizar la tarea del programación se describen a continuación las interfaces de los distintos
módulos.

** ESTRUCTURAS DE DATOS (Estr_Dat):

Constantes:
const MedidaHeap=100; máxima cantidad de elementos que puede manejar el heap.
const MedidaColas=150; máxima cantidad de elementos que puede manejar la cola.

Tipos:
struct TPtr{
unsigned bajo,
alto;
};

struct TipoNodo{ formato del reg. del nodo del HEAP


void *obj;
float tiempo;
};

Definición de clases:
class ClsHeap{
public:
ClsHeap();
void poner(void *datos, float r);
void *sacar();
void sacar2(void **datos, float *r);
void *primero();
int vacio();
int vacia();
int AlturaHeap(int raiz);
~ClsHeap();
protected:
void ErrorLLeno();
void ErrorVacio();
public:
int ultimo;
TipoNodo heap[MedidaHeap];
};

Pág. 18 de 20
class ClsLIFO{ // Clase para el manejo de una pila de objetos (punteros)
public:
ClsLIFO();
void ClsLIFOIni(unsigned TamMinCola, float FactorAmpl);
void poner(void *obj);
void *sacar();
void *primero();
int vacia();
~ClsLIFO();

protected:
virtual void ErrorLLena();
virtual void ErrorVacia();
virtual void ErrorTamMin(unsigned TamMin);
virtual void ErrorFacAmpl(float factor);

public:
void **V, // puntero al vector din mico de punteros
**ultimo; // puntero a la próxima entrada libre para ingresar
// un nuevo elemento a la cola
unsigned CantElem; // cantidad de elementos actuales en el vector
float FacAmpl; // factor de ampliaci¢n del vector din mico
};

class ClsFIFO: public ClsLIFO{// Clase para el manejo de una lista de objetos (punteros)
public:
ClsFIFO();
void ClsFIFOIni(unsigned TamMinCola, float FactorAmpl);
void *sacar();
void *primero();
~ClsFIFO();
protected:
virtual void ErrorLLena();
virtual void ErrorVacia();
virtual void ErrorTamMin(unsigned TamMin);
virtual void ErrorFacAmpl(float factor);

public:
void **primer; // dirección al primer elemento de la cola
};

class ClsConj: public ClsLIFO{// Clase para el manejo de una lista de objetos (punteros)
public:
void sacar(void *obj);
void *SacarUltimo();
int pertenece(void *obj);
Pág. 19 de 20
int vacio();

protected:
virtual void ErrorLLena();
virtual void ErrorVacia();
virtual void ErrorNoEncontrado();
virtual void ErrorTamMin(unsigned TamMin);
virtual void ErrorFacAmpl(float factor);
};

** SIMULACION (LSOOSIM):
Es más conveniente revisar el fuente de este módulo. Las operaciones de corrutinas no tienen ninguna
diferencia con la versión Pascal. El módulo agrega una idea interesante: DEBUG, variable del pre-procesador que
al definirla en nuestro fuente permite la depuración en tiempo de ejecución (una vez más, lea el fuente LSOOSIM
y el ejemplo suministrado).

Note la ausencia (si hacemos una comparación con PSOO para Pascal) de las unidades de monitoreo,
distribución y semáforos. Así mismo, la gestión de corrutinas está integrada en el módulo de simulación
(LSOOSIM) por lo que no aparece como una distinta.

Pág. 20 de 20

También podría gustarte