Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Programacion Oo VB PDF
Programacion Oo VB PDF
Resumen
La programación en Visual Basic se puede realizar de diversas formas o estilos. Este lenguaje nace
como un ambiente de prototipación rápida (RAD) para aplicaciones bajo el sistema operativo
Microsoft Windows. La orientación a objetos se incorpora como un elemento posterior al
nacimiento del lenguaje y actualmente (versión 5) no está totalmente soportada.
A pesar de lo anterior, Visual Basic permite la aplicación de los conceptos de orientación a objetos,
aunque esto no corresponda a un mapeo directo. Acá se presenta una técnica que permite programar
en forma estándar, basándose un modelo de clases UML. Por otra parte los conceptos que se
plantean son fácilmente aplicables a otros lenguajes de programación visuales.
Además de cumplir con el paradigma de la orientación a objetos, se presentan acá formas de
programación que cumplen con una arquitectura de tres capas. De esta forma, la lógica, en
términos de reglas del negocio, se aisla de los elementos de interfaz y de la forma de
almacenamiento de los objetos. Bajo este tipo de arquitectura, es posible separar físicamente estos
componentes del negocio, pudiéndose centralizar en servidores especializados, a través del uso de
monitores transaccionales como Microsoft MTS.
Arquitectura de 3 capas.
El objetivo principal de este planteamiento es separar y, por lo tanto independizar, las reglas del
negocio de las aplicaciones que las utilicen. De esta forma, es posible utilizar las mismas reglas del
negocio para diferentes aplicaciones, corriendo sobre distintas plataformas.
La capa de aplicación corresponde a programas interactivos o procesos, que
Capa de realicen alguna acción sobre los componentes del negocio. La capa
Aplicación intermedia estará formada por las clases del negocio, quienes interactúan con
el medio de almacenamiento que está repreentado en la capa de datos.
Una arquitectura pura de tres capas no permite ninguna forma de
comunicación directa entre la aplicación y la capa de datos; esto es, entre los
Capa del programas de usuario y la base de datos. Los programas de aplicación deben
Negocio solicitar todos sus requerimientos a la capa del negocio, a través de la
invocación de servicios, que corresponden a los métodos definidos para cada
clase.
Capa de Datos La separación propuesta por este modelo de capas nos da una clara guía de la
forma en que podemos enfrentar la programación de un sistema en Visual
Basic.
1
End Property
Uso de colecciones
Una colección es un tipo de objeto definido en el lenguaje. Este objeto es capaz de contener otras
variables tipo Variant, las que a su vez pueden ser otros objetos.
Los servicios que contiene una colección son Add, Remove y Count. Además es posible buscar
elementos dentro de una colección a través de una clave que se debe dar en el momento en que
éstos se agregan (como parámetro en el método Add).
Otro servicio especial de las colecciones es un iterador el que permite recorrer sus objetos mediante
sentencias “for each”. Por ejemplo:
Dim A1 As New Articulo, A2 As New Articulo, A3 As New Articulo
‘.. Inicialización de A1,A2 y A3.
Dim Col As New Collection
2
Dim A As Articulo
Col.Add A1
Col.Add A2
Col.Add A3
Set A1 = Nothing
Set A2 = Nothing
Set A3 = Nothing
“dsn=Bodega;uid=sa;pwd=”
Esta cadena de conexión indica los parámetros para que un objeto rdoConnection se conecte a la
base de datos requerida.
Los objetos más utilizados de la biblioteca rdo son rdoConnection, rdoQuery y rdoResultSet.
Supongamos que en la base de datos de bodega existe una tabla llamada “Bodega” con un campo
código y uno descripción. El código necesario para encontrar una bodega es el siguiente:
Conex.Connect = "dsn=Bodega;uid=sa;pwd="
3
Q(0).Type = rdTypeCHAR
Q(0).Value = "B01"
Set R = Q.OpenResultset
Set R = Nothing
Set Q = Nothing
Set Conex = Nothing
Exit Sub
ErrorEnConexion:
MsgBox "Error al conectarse: " & Err.Description
A un objeto Query es posible indicarle una consulta con parámetros, como en el ejemplo anterior.
En este caso, se le debe indicar un valor a cada uno de ellos y es conveniente también indicarle un
tipo de dato definido en ODBC. La asignación del tipo y valor se realiza directamente sobre el
objeto Query, usando el orden del parámetro como sub índice que comienza desde cero. En el
ejemplo anterior, Q(0).Type y Q(0).Value.
Es posible recorrer conjuntos de resultados provenientes de una consulta empleando el servicio
MoveNext de los objetos ResultSet, en conjunto con el método EOF.
4
Modelo de Clases
5
Modelo de Datos E-R
6
Debido a que se programa una capa intermedia que se desea utilizar desde diferentes tipos de
aplicaciones, desde Visual Basic creamos un nuevo proyecto del tipo “ActiveX dll”. De esta forma
las clases públicas que se definan en él podrán ser creadas y utilizadas desde otros proyectos Visual
Basic, desde macros Word o Exel, desde páginas Web vía ASP, o cualquier ambiente que soporte
el estándar ActiveX.
Por cada una de las clases definidas en el sistema, se crea su correspondiente módulo de clases en el
proyecto que creamos. El nombre de las clases no puede ser igual al nombre del proyecto.
En cada módulo de clases definiremos variables públicas, variables privadas, propiedades y
métodos.
En primer lugar, en cada clase podemos declarar una variable para mantener una referencia a la
conexión a la Base de Datos. Declaramos entonces al inicio de cada clase:
Dim Conex As rdoConnection
Esta variable deberá ser asignada desde la aplicación u otras clases cada vez que se creen nuevos
objetos y se usen sus servicios.
Por cada uno de los atributos definidos en el modelo de clases, podemos declarar una variable
pública en el módulo de la clase correspondiente.
Por otro lado, por cada uno de los campos de la tabla asociada en el modelo de datos que se utilice
como clave foránea hacia otra tabla, declaramos atributos privados. La declaración de variables de
la clase Movimiento quedaría entonces como:
Las clases se instanciarán (asignarán valores a sus variables) desde objetos del tipo ResultSet.
Podemos entonces crear en todas las clases un servicio public que instancie sus atributos desde un
ResultSet abierto y posicionado sobre una fila. Escribimos entonces para cada una de las clases un
servicio “LlenaDesdeResultSet”.
En el caso de la clase Movimiento, el servicio sería:
Public Sub LlenaDesdeResultSet(ByRef RS As ResultSet)
If Not RS.EOF Then
FechaHora = RS.rdoColumns(“FechaHora”)
Cantidad = RS.rdoColumns(“Cantidad”)
BodegaCodigo = RS.rdoColumns(“BodegaCodigo”)
ArticuloCodigo = RS.rdoColumns(“ArticuloCodigo”)
End If
End Sub
Cada una de las clases necesitará crear, destruir, modificar y leer sus objetos. Por ello podemos
crear estos cuatro servicios para todas las clases, aunque no estén definidos en el modelo. En el
caso de la clase Movimiento:
CreaObjeto: Se supone que las variables del objeto ya están instanciadas con los valores del nuevo
objeto que se desea crear.
7
Dim Q As New rdoQuery
Dim stSQL As String
Q.SQL = stSQL
Q(0).Type = rdTypeTIMESTAMP
Q(0).Value = FechaHora
Q(1).Type = rdTypeNUMERIC
Q(1).Value = Cantidad
Q(2).Type = rdTypeNUMERIC
Q(2).Value = BodegaCodigo
Q(3).Type = rdTypeNUMERIC
Q(3).Value = ArticuloCodigo
Q.Execute
Set Q = Nothing
End Sub
Q.SQL = stSQL
Q(0).Type = rdTypeTIMESTAMP
Q(0).Value = FechaHora
Q(1).Type = rdTypeNUMERIC
Q(1).Value = BodegaCodigo
Q(2).Type = rdTypeNUMERIC
Q(2).Value = ArticuloCodigo
Q.Execute
Set Q = Nothing
End Sub
8
Dim Q As New rdoQuery
Dim stSQL As String
Q.SQL = stSQL
Q(0).Type = rdTypeNUMERIC
Q(0).Value = Cantidad
Q(1).Type = rdTypeTIMESTAMP
Q(1).Value = FechaHora
Q(2).Type = rdTypeNUMERIC
Q(2).Value = BodegaCodigo
Q(3).Type = rdTypeNUMERIC
Q(3).Value = ArticuloCodigo
Q.Execute
Set Q = Nothing
End Sub
RecuperaEstado: Conociendo los atributos que forman la clave primaria (Oid u Object Id.) de un
objeto, es posible recuperar el valor del resto de ellos.
Q.SQL = stSQL
Q(0).Type = rdTypeTIMESTAMP
Q(0).Value = FechaHora
Q(1).Type = rdTypeNUMERIC
Q(1).Value = BodegaCodigo
Q(2).Type = rdTypeNUMERIC
Q(2).Value = ArticuloCodigo
Set RS = Q.OpenResultSet
Me.LlenaDesdeResultSet RS
Set RS = Nothing
Set Q = Nothing
End Sub
Con la definición de estos cuatro servicios, la persistencia de los objetos se puede manejar desde las
aplicaciones (u otros servicios) sin necesidad de realizar consultas SQL.
9
Se desea que la capa intermedia represente fielmente al modelo de clases que define la estructura
del sistema. Por ello, para cada una de las relaciones de una clase, vamos a crear propiedades en
ella, que permitan a las aplicaciones o servicios de otras clases navegar por el modelo.
Las relaciones en un modelo de clases se definen con nombres de roles, dependiendo de la dirección
de la navegación. Si en el modelo no se han definido, podemos suponer que se utilizan los mismos
nombres de las clases, en singular o plural, dependiendo de la cardinalidad. Por ejemplo, desde
Bodega a Movimiento el nombre sería “Movimientos” y desde Movimiento a Bodega, “Bodega”.
Ocupando estos nombres de relaciones, escribiremos propiedades que permitan retornar él o los
objetos relacionados.
Para la clase Movimiento:
Set RS = Q.OpenResultSet
Set ObjetoRelacionado.Conex = Me.Conex
ObjetoRelacionado.LlenaDesdeResultSet RS
Set RS = Q.OpenResultSet
RS.MoveNext
Set ObjetoRelacionado = Nothing
Loop
Set RS = Nothing
Set Q = Nothing
End Property
10
Para el caso de especializaciones o herencias, se pueden utilizar como nombre para las propiedades:
“Padre” desde la clase hija a la padre, y el nombre de la clase hija en la dirección contraria. En este
último caso y en las asociaciones que aceptan cardinalidad cero, la propiedad debe ocuparse de que
los objetos relacionados no existan, pudiendo retornar objetos nulos (asignándoles la constante
Nothing).
Utilizando estas propiedades, se puede accesar en forma muy fácil a los objetos relacionados a
alguno en particular. Si se escribieran estas propiedades para todas las relaciones del modelo, las
navegaciones compuestas resultan en forma natural, como en el siguiente ejemplo:
Conex.Connect = “dsn=Bodega;uid=sa;pwd=”
Conex. EstablishConnection rdDriverNoPrompt
Set Bodega.Conex = Conex
Bodega.Codigo = “B01”
Bodega.RecuperaEstado
Las propiedades que escribimos nos permiten consultar por objetos relacionados, pero hay
ocaciones en que es necesario asignar valores a estos objetos. Por ejemplo, antes de crear un
Movimiento, es necesario asignar la Bodega y El Artículo ya que (como es agregación) forman
parte de su Oid. Para ello, para las relaciones con origen en una clase (cardinalidad 0..* => 1)
creamos propiedades que permitan asignar el objeto relacionado. Lo mismo se debe realizar para
permitir la asignación del objeto padre cada vez que se crea un hijo.
En la clase Movimiento:
Entonces, antes de crear un nuevo movimiento, se asignan los objetos relacionados. Por ejemplo, si
queremos crear un nuevo movimiento de entrada para una bodega, artículo y proveedor ya
instanciados, podemos escribir:
11
Dim Mov As New Movimiento, Ent As New Entrada
El lenguaje Visual Basic no soporta la herencia de objetos; sin embargo, ésta se puede simular
utilizando “funciones espejo.” Si tenemos una propiedad llamada “Padre” que retorne el objeto
asociado de la clase padre, podemos escribir en el hijo, propiedades que representes a los atributos,
servicios y relaciones de la clase padre. En el ejemplo anterior, para la clase Entrada:
Si la clase padre a su vez heredara de otra más, sería necesario en la nieta declarar funciones espejo
para representar los atributos, relaciones y servicios de la clase abuela.
El resto de los servicios de las clases se escriben utilizando las propiedades y servicios de
persistencia que antes se definieron. En el ejemplo anterior, se necesita defnir los servicios de
Entrada y Salida de artículos para la clase Bodega.
12
‘ Crear el objeto Entrada como hijo de Mov
Set Ent.Conex = Me.Conex
Set Ent.Padre = Mov
Set Ent.Proveedor = Proveedor
Ent.CreaObjeto
‘ Destruir variables
Set Sto = Nothing
Set Ent = Nothing
Set Mov = Nothing
End Sub
13
‘ Limpiar variables
Set Sal = Nothing
Set Sto = Nothing
Set Mov = Nothing
End Sub
Como se está construyendo bajo una arquitectura de tres capas, el servicio Salida no puede
desplegar un mensaje cuando la cantidad requerida es mayor que la disponible. La forma de avisar
los errores es empleando el estándar que provee ActiveX, a través del objeto Err. Este error puede
ser capturado (usando “On Error Goto”) desde la aplicación que invoca el servicio y es ella la
encargada de avisarlo al usuario.
Es conveniente crear algunos servicios especiales en las clases que faciliten la construcción de
interfaces. Por cada clase podemos crear propiedades (Get y Set) que permitan recuperar y asignar
la identificación de los objetos para poder referenciarlos desde las aplicaciones. Definamos
popiedades llamadas “Oid” para cada una de las clases. En el caso de Movimiento:
Public Property Get Oid() As Collection
Set Oid = New Collection
Oid.Add FechaHora
Oid.Add BodegaCodigo
Oid.Add ArticuloCodigo
End Property
Una aplicación puede declarar una variable tipo colección u object para almacenar la clave de un
objeto y luego asignársela a éste de vuelta para recuperar su estado.
Otros servicios útiles para la construcción de interfaces serían aquellos que retornan colecciones de
objetos para mostrar en algún control. Debido nuevamente a la arquitectura de tres capas, no
deseamos que la aplicación accese a la base de datos, pero podemos construir servicios en la capa
intermedia que nos retornen grupos de objetos para mostrarlos en las ventanas, y permitir que el
usuario los seleccione.
Por ejemplo, podemos construir un servicio “Todas” en la clase bodega, de la forma:
14
Set Q = Nothing
End Function
15
Programación de la Capa de Aplicación.
La capa de aplicación corresponde a la interfaz con el usuario. Ella puede sólo accesar a objetos de
la capa del negocio y no directamente a la base de datos, por lo que no se debría escribir consultas
SQL o reglas del negocio dentro de los eventos de controles o elementos de interfaz.
Para la construcción de una aplicación, partimos con un nuevo proyecto en Visual Basic del tipo
“Standard EXE”. Dentro del ambiente integrado de programación, podemos tener abiertos más de
un proyecto a la vez, en un grupo de proyectos. Podemos agregar un proyecto nuevo “File|Add
project” al grupo y de esta forma tener en un mismo ambiente la capa intermedia (ActiveX dll) y la
aplicación (Standard EXE).
Seleccionando el proyecto de la aplicación agregamos una referencia hacia el proyecto de las clases
(Project|References). De esta forma, la capa intermedia constituye una biblioteca para la aplicación.
Desde el formulario principal de la aplicación podemos crear una conexión pública (un objeto
rdoConecction). Esta conexión se irá asignando a los objetos y otros formularios, a medida que se
vayan creando.
Mantención de objetos.
Una de las tareas comunes a todos los sistemas corresponde a la mantención de los datos que actúan
como “maestros”. En el ejemplo anterior, podemos realizar la mantención de las bodegas en el
siguiente formulario:
16
End If
End Sub
ListaBodegas.Clear
For Each B In Todas
ListaBodegas.AddItem B.Descripcion
Next
End Sub
Los formularios para Agregar y Modificar una bodega tendrán el código necesario en su botón de
“Aceptar” para llamar a los servicios CreaObjeto y DestruyeObjeto, respectivamente.
Si un formulario necesita ejecutar servicios que como parámetros reciban otros objetos, éstos
últimos se pueden seleccionar desde listas o “ComboBox” como en el ejemplo anterior. Además de
los controles listbox, se pueden utilizar controles como el FlexGrid o el ListView que permiten
mostrar más columnas. Estas otras columnas pueden mostrar otros atributos del objeto o atributos
de objetos relacionados, usando las propiedades que se programaron en la capa intermedia.
Por ejemplo, si se muestran los movimientos a una bodega, las columnas se podrían llenar con el
siguiente código:
17
Else
Grilla.String(Fila,4)=
Movimiento.Salida.Destinatario.Descripcion
End If
Next
Entonces, al inicio de cada servicio, las clases pueden siempre llamar a Conecta.
La sentencia New se reemplaza por la creación directa de los objetos, usando CreateObject. Por
ejemplo, si en el caso anterior llamamos al proyecto “ClasesBodegas” que contiene una clase
“Bodega”, la creación de un objeto y su conexión a la base de datos, sería de la forma:
Dim Bod
18