jueves, 21 de agosto de 2008

Terecer Apunte Programacion II

Programación orientada a objetos.

Es un paradigma basado en la identificación de los objetos inherentes al problema y en la escritura del código que modelan a esos objetos, sus propiedades, sus comportamientos y la forma en que se relacionan para resolver un problema.
La POO, resulta opuesta a la programación imperativa clásica, donde los programas son secuencias de instrucciones.
En la actualidad, los lenguajes de plataforma .NET, se basan en la definición de clases y objetos, pero conservan características de la programación imperativa.
La POO es una evolución de la programación estructurada.
Además conduce a un modelo mental del problema, mucho más cercano a la realidad, favoreciendo el análisis, implementación y posterior mantenimiento del software.
Otra ventaja es que la POO permite lograr un mayor grado de encapsulado, ya que el comportamiento y los datos propios de la clase, quedan contenido en la definición de ella.

Clases y Objetos

Un OBJETO se caracteriza por tener un estado, que son el conjunto de valores de sus propiedades en un momento de tiempo,(por EJ. En nombre de un empleado o el monto de sueldo que percibe).
Además, todo Objeto tiene un Comportamiento, es decir, las acciones que puede realizar y que modificarán su estado (EJ. Un empleado puede ascender de categoría).
Un objeto se caracteriza por tener identidad propia, es decir, por más que dos objetos tengan el mismo comportamiento y el mismo estado, resultan totalmente diferentes e identificables.

Una CLASE, es un grupo de elementos de un conjunto, que tienen características comunes.
Las técnicas de orientación a objetos, se centran en la identificación de esos elementos comunes entre los objetos, para poder agruparlos en clases y así poder manipularlos.

Por ej. Pensemos en una mesa. Hay mesas redondas, rectangulares, de madera, de metal, de diversos colores. Todas son mesas distintas e identificables, es decir, Objetos.
Sin embargo, podemos verificar que todas tienen los mismos atributos, aunque con distintos valores. Todas tiene un color, una forma, un material; por lo tanto, por lo tanto, podemos agruparlas bajo un mismo concepto: La Mesa.
Desde el punto de vista de la Orientación a Objetos, podemos decir que MESA, es una clase.
















Propiedades y Métodos

Los Atributos del Objeto, son las Propiedades que los modelan.
El Comportamiento, en cambio, está representado por procedimientos y funciones dentro de la clase.
Los procedimientos y funciones que creamos dentro de la clase, se denominan Métodos y representan las actividades que un objeto puede realizar, o sea, su comportamiento.
Los Métodos son encargados de interceptar y enviar mensajes desde y hacia otros objetos y al mismo tiempo, alterar el estado actual del objeto.

Pensar en Objetos.

La forma de solucionar problemas utilizando técnicas de orientación a objetos, es muy distinta de la forma tradicional o estructurada.
Cuando nos presentan un requerimiento de una nueva aplicación y queremos aplicar los conceptos de la POO, como primer paso nos concentraremos en identificar los objetos que intervienen en el problema. Deberemos entonces, analizar cuidadosamente el requerimiento, hablar con los usuarios y prestar especial atención a los elementos que mencionan. Una técnica muy usada, consiste en leer el requerimiento escrito (que deberá ser lo más claro y completo posible), y subrayar todos los sustantivos, tanto concretos como abstractos. Luego, de entre todos los sustantivos subrayados, descartamos aquellos que no son propios del problema a resolver.
Esos sustantivos subrayados, serán los potenciales objetos que integrarán nuestra aplicación.

Por ejemplo, imaginemos que necesitamos implementar una aplicación de alquiler de autos y nos presentan el siguiente requerimiento (resumido): “La empresa dispone de autos para alquilar a sus clientes. Cuando se alquila un auto, el cliente firma una póliza de seguro. En un formulario de alquiler, se registrar la fecha, la hora, el nombre del cliente, el número de su registro de conductor y el número de su tarjeta de crédito”.
Si aplicamos la técnica de los sustantivos, podremos identificar rápidamente tres objetos fundamentales para la aplicación: Auto, cliente y formulario de alquiler.dependiendo del tipo de análisis y diseño que queremos hacer, podríamos considerar como objetos la tarjeta de crédito, e incluso, el alquiler.

Para identificar las propiedades aplicamos una técnica similar a la de los sustantivos, pero buscando cualidades o adjetivos de los objetos que ya identificamos. Por ej. El formulario de alquiler tiene propiedades como: fecha, nombre del cliente, etc.

Una vez que hemos identificado los objetos y sus propiedades, estamos en condiciones de definir clases para agruparlos y abstraer todas las posibles instancias de ellos. Hemos alcanzado así el fin de la primera etapa en el proceso de solución de problemas mediante técnicas de orientación a objetos.











Relaciones entre Clases

Todo Objeto, se relaciona en cierta medida, con alguno de los otros objetos (sea o no, de la misma clase). En el ejemplo de alquiler de autos, los clientes se relacionaron con los autos (que también son Objetos), mediante la operación de alquiler. Del mismo modo, los formularios de alquiler se relacionan con los autos y los clientes. Si un Objeto no se relaciona con otro, es probable que no sea necesario tenerlo en el sistema. Un Objeto, puede relacionarse con otro, de distintas maneras, como por ejemplo, enviándose mensajes entre si.
Ej de relaciones entre Objetos:

a) Relación de Uso: En una relación de uso, una Objeto A, usa un Objeto B, en el sentido de utilizar algún servicio provisto por B. En cualquier aplicación es muy común encontrar que un Objeto necesita algún servicio de otro, como pedirle que haga una determinada tarea.

b) Relación de agregación: Muchas veces un Objeto se compone de otros. Este tipo de relación se denomina, agregación. En esta relación, un grupo de Objetos (de la misma clase o clases distintas), se agrupan para formar un objeto más complejo. Ejemplo: Un carrito de compras, se compone de uno o más productos que el cliente ha comprado. Si bien los Objetos producto, son independientes, el objeto carrito, necesita de ellos para existir. La relación de agregación, puede ser recursiva, es decir, un objeto que está compuesto por otros, a su vez, puede ser parte de un objeto más grande. EJ. Una Universidad, puede estar compuesta por facultades y esas facultades se componen de departamentos.

c) Relación de Composición: Es un caso especial de agregación, en el que los Objetos agregados a otro, solo pertenecen a él. Por EJ. Un automóvil, está compuesto de un motor, un chasis, una carrocería y otros elementos, pero cada uno de ellos, solo puede pertenecer a ese auto. El motor de un auto, no puede pertenecer a otro.


Principios de orientación a Objetos
En POO, los datos y el código de manipulación de esos datos, están juntos en una única entidad que se denomina Objeto.
Un objeto, es una colección de elementos de datos y procedimientos de software, que permiten manipularlos. En Visual B. y en otros lenguajes de programación, el diseño de un objeto, se realiza sobre una Clase.
La clase es el molde del cual se crean los objetos, por lo que un objeto, es una instancia en memoria de una clase. Los términos de clase y objeto, tienen distintos significado en el contexto de la programación: uno se enfoca en la representación en diseño, mientras que el otro en el uso durante la ejecución del programa. Siempre programaremos clases y crearemos objetos a partir de esas clases.
Los objetos, se deberían construir, siguiendo los cuatro principios de la orientación a Objetos: Abstracción, Encapsulamiento, Herencia y Polimorfismo.

Abstracción: La abstracción, es el proceso por el cual obtenemos, de una entidad de la vida real, sus características fundamentales en una situación particular.
Esto nos permitirá modelar los objetos en código y proporcionar su funcionalidad y comportamiento.
Supongamos que debemos crear un componente que mantenga la información de un empleado.
Como proceso de abstracción, debemos identificar las características de la entidad que nuestro componente debería mantener bajo su control.

Ejemplo:

Nombre y apellido
Fecha Nacimiento
Antigüedad
Categoría
N° legajo
Sueldo
Etc

La abstracción, no solo identifica valores y datos que debe mantener la entidad, sino también los factores y las acciones que pueden hacer cambiar esos datos. Esta abstracción del empleado, se representará en una clase Empleado y los elementos identificados, se convertirán en miembros de la clase. Los elementos de datos, conformarán sus campos y propiedades (estado del objeto), y las acciones y reacciones, en métodos y eventos (comportamiento del objeto).

Encapsulamiento: El encapsulamiento, es el proceso por el cual, nuestro componente de software, se comporta como una caja negra, exponiendo como público, solo lo necesario y ocultando la complejidad del procesamiento interno hacia el exterior.
De esta manera, vemos lo que el objeto es capaz de hacer, pero no cómo lo hace, es decir, su funcionalidad está encapsulada en si misma.
El encapsulamiento proporciona varias ventajas:
Protege la modificación de los datos internos directamente
Da la posibilidad de incluir controles de error y validación
El usuario del objeto, debe preocuparse por entender que hace el objeto y no cómo lo hace.

Herencia:
La herencia, es el mecanismo por el cual, una clase obtiene toda la funcionalidad de otra, denominada clase Base. Esto da la posibilidad de reutilizar lo ya existente, sin necesidad de escribirla de nuevo.
El uso de la herencia hace que nuestros programas sean más compactos y extensibles.

En Visual Basic .NET las clases se definen utilizando la siguiente sintaxis:
Public Class
.
. .
End Class
Para que una Clase herede la interfaz y comportamiento de otra Clase existente se utiliza la palabra clave reservada Inherits.

Polimorfismo: Es la habilidad de comportarse de manera distinta según el contexto en el cual estoy trabajando. El Polimorfismo permite a los objetos de diferentes clases, responder apropiadamente a nombres u operadores de métodos idénticos, el polimorfismo permite también, utilizar nombres compartidos y el sistema podría aplicar el código apropiado para un objeto particular.






Miembros de una Clase

Campos
Los campos proveen almacenamiento para los datos en un objeto y son tratados como variables, usualmente son privados.
 Si los campos son declarados Private se hacen visibles sólo para los métodos dentro de la clase, lo cual incrementa el ocultamiento de los datos y minimiza la posibilidad de efectos colaterales.
Propiedades
Los campos privados de una clase NO pueden ser accesados por código externo, por lo que si es requerido que los campos sean leidos o cambiados, para ello será necesario incluir procedimientos de propiedades (property procedures) en la definición de la clase.
Los procedimientos de propiedades dan el control de clase sobre como los campos son asignados o regresados. El nombre del procedimiento de propiedad es hecho visible al código externo.
El procedimiento de propiedad Get tipicamente recupera un campo privado.
El procedimiento de propiedad Set tipicamente asigna un nuevo valor al campo privado.
Para que un código externo pueda ver el valor de un campo pero no pueda cambiar su valor es necesario que el campo sea sólo de lectura, lo cual es posible antecediendo al nombre del procedimiento de propiedad la palabra reservada ReadOnly, entonces VB.NET podría omitir el bloque Set/End Set porque es innecesario.

[ReadOnly] property nombrePropiedad as tipoDato
Get
return nombreCampo
End Get
[Set(ByVal valor as tipoDato)
nombreCampo = valor
End Set]
End Property

Métodos
Los métodos son procedimientos definidos dentro de la clase. Los procedimientos tienen acceso a todos los datos dentro del objeto incluso si son privados.

[Private|Public] Sub nombreMetodo([parámetros])
sentencias
End Sub

[Private|Public] Function nombreMetodo([parámetros]) as tipoDato
sentencias
End Function

Agregar una Clase

La definición de una clase consiste de campos, propiedades y métodos, un campo es una variable en la clase y usualmente es privada, una propiedad es una programación constructora que tipicamente provee la interfaz para un campo en una clase, una propiedad contiene procedimientos especiales Get y Set que permiten al código externo hacer referencia al campo en un sentido que mantiene la encapsulación de datos, un método es una función o procedimiento dentro de una clase. La definición de la clase puede también contener métodos constructores (mas adelante lo veremos mas en detalle), que son invocados cuando un nuevo objeto es instanciado desde una clase. Es conveniente listar primero los campos, después las propiedades y los métodos constructores y por último cualquier otro método adicional.

Private|Public Class nombreClase
campos
propiedades
constructores
métodos
End Class


Comenzaremos a modo de ejemplo, definiendo las partes que integran una clase y crearemos una interfaz para su implementación.
En Visual Basic .NET para agregar una Clase seleccione: Proyecto/agregar Clase, elija un formulario CLASE y modifique el nombre genérico Class1.
Ejemplo de cómo definimos campos en una clase.

Public Class Persona
Private sNombre As String
Private nEdad As Integer
Private bSexo As Boolean
End Class







¿Cómo declarar una propiedad como un procedimiento Property?

Para estos casos, el compilador de Visual Basic .NET pone a nuestra disposición una instrucción, que al igual que Sub o Function, nos permiten declarar un procedimiento que tiene un trato especial, este es el caso de Property.
La forma de usar Property es muy parecido a como se declara una función, pero con un tratamiento especial, ya que dentro de esa declaración hay que especificar por un lado lo que se debe hacer cuando se quiera recuperar el valor de la propiedad y por otro lo que hay que hacer cuando se quiere asignar un nuevo valor.
Cuando queremos recuperar el valor de una propiedad, por ejemplo para usarlo en la parte derecha de una asignación o para usarlo en una expresión, tal es el caso de que queramos hacer algo como esto: Dim s As String = p.Nombre
O como esto otro: Console.WriteLine(p.Nombre)
En estos dos casos, lo que queremos es recuperar el contenido de la propiedad.
Pero si lo que queremos es asignar un nuevo valor, esa propiedad normalmente estará a la izquierda de una asignación, como sería el caso de hacer esto:
p.Nombre = "CRISANTEMO". En este caso estaríamos asignando un nuevo valor a la propiedad Nombre.
Si queremos que Nombre sea realmente una propiedad (un procedimiento del tipo Property) para que podamos hacer ciertas comprobaciones tanto al asignar un nuevo valor como al recuperar el que ya tiene asignado, tendremos que crear un procedimiento como el que mostramos a continuación:
1er ejemplo de uso :

Public Property Nombre() As String
' la parte Get es la que devuelve el valor de la propiedad
Get
Return elNombre
End Get
' la parte Set es la que se usa al asignar el nuevo valor
Set(ByVal Value As String)
If Value <> "" Then
elNombre = Value
End If
End Set
End Property


Ejemplo de interfaz:

nombre.Nombre = TextBox1.Text
Label1.Text = nombre.Nombre

Es decir, declaramos un procedimiento del tipo Property, el cual tiene dos bloques internos:
El primero es el bloque Get, que será el código que se utilice cuando queramos recuperar el valor de la propiedad, por ejemplo para usarlo en la parte derecha de una asignación o en una expresión.
El segundo es el bloque Set, que será el código que se utilice cuando queramos asignar un nuevo valor a la propiedad, tal sería el caso de que esa propiedad estuviera en la parte izquierda de una asignación.
Como puedes comprobar, el bloque Set recibe un parámetro llamado Value que es del mismo tipo que la propiedad, en este caso de tipo String. Value representa el valor que queremos asignar a la propiedad y representará lo que esté a la derecha del signo igual de la asignación. Por ejemplo, si tenemos esto: p.Nombre = "Guillermo", "Guillermo" será lo que Value contenga.

Nota:
En el caso de Visual Basic .NET, el parámetro indicado en el bloque Set se puede llamar como queramos (NO SOLO VALUE).
Fíjate que cuando creamos un procedimiento Property siempre será necesario tener un campo (o variable) privado que sea el que contenga el valor de la propiedad. Ese campo privado lo usaremos para devolver en el bloque Get el valor de nuestra propiedad y es el que usaremos en el bloque Set para conservar el nuevo valor asignado.
Ni que decir tiene que el tipo de datos del campo privado debe ser del mismo tipo que el de la propiedad.
La ventaja de usar propiedades declaradas como Property en lugar de usar variables (o campos) públicos es que podemos hacer comprobaciones u otras cosas dentro de cada bloque Get o Set, tal como hemos hecho en el ejemplo de la propiedad Nombre para que no se asigne una cadena vacía al Nombre.
Nota:
De todas formas, no es recomendable hacer mucho "trabajo" dentro de una propiedad, sólo lo justo y necesario.
Si nuestra intención es que dentro de una propiedad se ejecute un código que pueda consumir mucho tiempo o recursos, deberíamos plantearnos crear un método, ya que las propiedades deberían asignar o devolver los valores de forma rápida.
Propiedades de sólo lectura.
Una de las ventajas de usar un procedimiento Property es que podemos crear propiedades de sólo lectura, es decir, propiedades a las que no se pueden asignar valores nuevos, simplemente podemos acceder al valor que contiene.
Para poder conseguir que una propiedad sea de sólo lectura, tendremos que indicárselo a Visual Basic .NET de la siguiente forma:


Private valorFijo As Integer = 10
'
Public ReadOnly Property Valor() As Integer
Get
Return valorFijo
End Get
End Property

Es decir, usamos la palabra clave (o modificador) ReadOnly al declarar la propiedad y tan sólo especificamos el bloque Get.
Si declaramos un procedimiento ReadOnly Property no podemos indicar el bloque Set, eso dará error.


Propiedades de sólo escritura.
De la misma forma que podemos definir una propiedad de sólo lectura, también podemos crear una propiedad de sólo escritura, es decir, una propiedad que sólo aceptará que se asignen nuevos valores, pero que no permitan obtener el valor que tienen... la verdad es que este tipo de propiedades no son muy habituales, pero podemos hacerlo.
Veamos cómo tendríamos que declarar una propiedad de sólo escritura.
Private valorEscritura As Boolean
'
Public WriteOnly Property Escribir() As Boolean
Set(ByVal Value As Boolean)
valorEscritura = Value
End Set
End Property

Es decir, usamos el modificador WriteOnly al declarar la propiedad y sólo debemos especificar el bloque Set.
Si declaramos un procedimiento WriteOnly Property no podemos indicar el bloque Get, ya que eso dará error.
Cuando declaramos una propiedad de sólo lectura no podemos declarar otra propiedad con el mismo nombre que sólo sea de escritura. Si nuestra intención es crear una propiedad de lectura/escritura, simplemente con no complicarnos la existencia es suficiente, es decir, declaramos la propiedad sin indicar ni ReadOnly ni WriteOnly.
Ejemplo de la Clase Persona:

Public Class Persona
Private sNombre As String
Private nEdad As Integer
Private bSexo As Boolean

Public Property Nombre() As String
Get
Return sNombre
End Get
Set(ByVal Value As String)
sNombre = Value
End Set
End Property

Public Property edad() As Integer
Get
Return nEdad
End Get
Set(ByVal Value As Integer)
nEdad = Value
End Set
End Property





Public Property sexo() As Boolean
Get
Return bsexo
End Get
Set(ByVal Value As Boolean)
bsexo = Value
End Set
End Property

Public Sub sexoPersona()
If bSexo Then
MsgBox("Hombre")
Else
MsgBox("Mujer")
End If
End Sub
End Class


Interfaz de la Clase Persona:

Dim Empleado As New Persona
Empleado.Nombre = txtNombre.Text
Empleado.edad = CInt(txtEdad.Text)
Empleado.sexo = txtSexo.Text
Empleado.sexoPersona()


Como puede notar las declaraciones de obtención y asignación de valores para las propiedades coinciden no en nombre ya que puede declarar la primer parte de las propiedades con un nombre y con otro la declaración de la propiedad por completo, es decir, la parte donde se asigna y recupera el valor, la única relación existente es por el valor que se asigna o por el valor que se regresa.
Atención es posible crear más de una Clase dentro de un módulo de Clase siempre y cuando las clases se encuentren delimitadas por las intrucciones de inicio (Public Class) y final (End Class) de la Clase.






Ejemplo de HERENCIA

Si desea crear una Clase que herede de la Clase Persona puede incluir en el mismo módulo de Clase Persona, la Clase que hereda, por ejemplo Director y escribir dentro del bloque de la clase la declaración que indica que hereda el comportamiento y propiedades de otra Clase a través de la palabra reservada Inherits.
Debajo del código de la Clase Persona escriba:

Public Class Director
Inherits Persona
Private sArea As String
Public Property Area() As String
Get
Return sArea
End Get
Set(ByVal Value As String)
sArea = Value
End Set
End Property
End Class

En su interfaz agregue:
empleado.Nombre = Textnombre.Text
empleado.edad = Val(Textedad.Text)
empleado.sexo = Textsexo.Text
directorgeneral.Nombre = Textdirector.Text
empleado.sexoPersona()
Label6.Text = empleado.Nombre
Label7.Text = directorgeneral.Nombre

Ámbito de las variables.

El ámbito es la cobertura o duración de la vida de una variable, un procedimiento o una clase, es decir, hasta dónde son visibles y, por decirlo de alguna forma, durante cuanto tiempo.
Hasta ahora hemos estado usando dos instrucciones (o modificadores) que permiten indicar el ámbito de un miembro de una clase (o módulo), uno de ellos es Public y el otro es Private. Como habrás podido comprobar, al usar el modificador Public, permitimos que el miembro al que se le ha aplicado ese modificador sea visible desde cualquier sitio y por tanto estará accesible para que podamos usarlo desde la propia clase o desde fuera de ella; por otro lado, cuando usamos Private, estamos indicando que ese miembro es "privado" a la clase en la que se ha declarado y por tanto sólo podremos usarlo desde la propia clase.
Antes de entrar en detalles y para que se comprenda mejor, vamos a verlo con un ejemplo:

Veamos el código :

Public Class Prueba15
Private elNombre As String
Public Apellidos As String
'
Public Property Nombre() As String
' la parte Get es la que devuelve el valor de la propiedad
Get
Return elNombre
End Get
' la parte Set es la que se usa al asignar el nuevo valor
Set(ByVal Value As String)
If Value <> "" Then
elNombre = Value
End If
End Set
End Property
'
' método público para mostrar el nombre completo
Public Sub Mostrar()
msgbox(elNombre & " " & Apellidos)
End Sub
End Class

En esta clase hemos definido dos campos: elNombre y Apellidos, el primero está declarado como Private, por tanto sólo será visible dentro de la clase, es decir: no podemos acceder a ese campo desde fuera de la clase. El segundo está declarado como Public, por tanto será accesible (o visible) tanto desde dentro de la clase como desde fuera de ella.
Decir que será visible o accesible, se refiere a la posibilidad de poder usarlo. Como es de imagina, para poder usar cualquier miembro de una clase "desde fuera", tendremos que declarar una variable del tipo de la clase e instanciarla por medio de New, ya que esta es la única forma de poder acceder a una clase, en este caso, cuando decimos clase, nos referimos a un "tipo" declarado usando Class.
En ese código que se ha mostrado, para poder acceder a los miembros de la clase, tendremos que crear una nueva instancia; pero a los miembros a los que podemos acceder, sólo serán los que estén declarados como Public.
Además de esos dos campos, también tenemos una propiedad y un método, ambos declarados como Public.
El método Mostrar, que es un procedimiento de tipo Sub, puede acceder tanto a la variable declarada como Private como a la que hemos declarado como Public, ya que ambas variables (en este caso también campos de la clase) tienen la "cobertura" suficiente para que sean vistas (o accesibles) desde cualquier sitio "dentro" de la propia clase.
La propiedad Nombre, tiene dos bloques de código, uno será la parte Get (la que devuelve el valor de la propiedad) y la otra es el bloque Set (el que asigna el valor a la variable privada). Desde los dos bloques podemos acceder a la variable privada elNombre, ya que el ámbito de dicha variable es: toda la clase.
Pero si te fijas, en el bloque Set de la propiedad se ha declarado una variable, esa variable sólo será "visible" dentro de ese bloque y no podrá ser accedida desde ningún otro sitio, en cuanto acabe ese bloque, la variable Value "desaparece" y deja de existir.

Cómo declarar las variables.

Para declarar una variable podemos hacerlo de varias formas, dependiendo dónde se declaren esas variables. Usando la misma nomenclatura que en la documentación de Visual Studio .NET, existen varios niveles de ámbito, es decir, existen distintos "sitios" en los que podemos declarar una variable, , estos niveles son:
Bloque: Un bloque puede ser, por ejemplo, un If... Then, un Do... Loop o los bloques Get y Set.
Procedimiento: Un Sub, Function o Property.
Módulo: Una clase (Class), módulo (Module) o estructura (Structure)
Espacio de nombres: Un bloque Namespace.
Los tipos de niveles están enumerados de menor a mayor, es decir, una variable declarada en un nivel de módulo, tendrá más cobertura que otra declarada en un bloque If.
Lo cual quiere decir que si declaramos una variable a nivel de módulo, esa variable será visible desde cualquier otro "nivel" inferior. Cosa que hemos comprobado en el código de la clase anterior. La variable elNombre declarada a nivel de módulo (en este caso el módulo es uno del tipo Class) es visible en un nivel inferior, en ese ejemplo podemos acceder a ella desde los dos procedimientos que tenemos, (sub y Property).
Como hemos visto, lo habitual para declarar una variable es usando Dim. De hecho, usar Dim es la única forma de declarar una variable en los dos niveles inferiores (bloque y procedimiento). Pero en el nivel de módulo podemos usar tanto Dim como las instrucciones Private, Public (y las que ahora veremos). Cuando declaramos una variable con Dim en un nivel de módulo es lo mismo que declararla con Private.

Las variables declaradas en los procedimientos.
Las variables en un procedimiento, (Sub, Function o Property), tenemos que declararlas con Dim. Esto significa que las variables son privadas (o locales) al procedimiento, por tanto sólo se podrán usar dentro del procedimiento y desde fuera de él no sabrán de la existencia de esas variables.
Pero aún hay más, si hubiese una variable de "nivel superior" que se llamase igual que una variable "local" al procedimiento, ésta última ocultaría a la que está declarada en un nivel superior.
Por ejemplo, en la clase Prueba15 tenemos la variable elNombre, declarada a nivel de módulo, ésta variable podrá usarse dentro del procedimiento Mostrar, pero si el procedimiento Mostrar lo re-escribimos de esta forma:

Public Sub Mostrar()
' prueba declarando una variable "local"
' que se llama igual que otra declarada a nivel de módulo
Dim elNombre As String
'
msgbox(elNombre & " " & Apellidos)
End Sub

La variable declarada dentro del procedimiento "ocultaría" a la declarada a nivel de módulo, por tanto, ahora no se mostraría el nombre que hubiésemos asignado a la clase, sino una cadena vacía, ya que no hemos asignado nada a esa variable.
Pero aún hay más, si el parámetro de un procedimiento recibe una variable que se llama como otra declarada a nivel superior, esa variable también ocultaría a la de nivel superior.
Por ejemplo, si tenemos este procedimiento:

Public Sub Mostrar2(ByVal elNombre As String)
msgbox(elNombre & " " & Apellidos)
End Sub

El nombre de la variable usada como parámetro también se llama igual que la declarada a nivel de módulo, por tanto esa variable (la del parámetro) ocultará a la otra (la declarada a nivel de módulo).
Cuando decimos que ocultará, nos referimos a que la variable solo "eclipsa" a la otra, no la sustituye, ya que realmente son dos variables diferentes y cada una tendrá su propia dirección de memoria, por tanto el valor asignado a esas variables locales no afectará en nada a la variable declarada a nivel de módulo.
Cuando declaramos variables locales (al procedimiento), éstas durarán (o existirán) mientras dure el procedimiento, es decir, cuando se sale del procedimiento, el valor que tuviera asignado, se perderá. Cuando se vuelva a entrar en el procedimiento se volverán a crear esas variables y el valor que antes tenían ya no será recordado.
Nota:
Cada vez que se usan las variables locales a un procedimiento (incluidos los parámetros declarados con ByVal), (o referencias en el caso de que sean tipos por referencia), estos valores se almacenan en una memoria especial llamada "pila", cuando se sale del procedimiento se "limpia" la pila y por tanto esas variables se pierden.
Pero, habrá ocasiones en que no queramos que esos valores de las variables locales se pierdan, en Visual Basic podemos hacerlo declarando las variables usando la instrucción Static en lugar de Dim.
Static le indica al compilador que esa variable debe mantener el valor entre distintas llamadas al procedimiento, para que de esa forma no se pierda el valor que tuviera.
Las variables declaradas con Static siguen siendo locales al procedimiento y también "ocultarán" a variables declaradas a nivel de módulo que se llamen de igual forma. Es decir, funcionan como las declaradas con Dim, pero mantienen el valor, además de que Static sólo se puede usar para declarar variables dentro de procedimientos.

Veamos un ejemplo que lo aclare.




Por ejemplo, si escribimos el siguiente código:

Module Modulo2
Sub Main()
Dim i As Integer
For i = 1 To 3
Prueba()
Next
End Sub

Sub Prueba()
Dim numDim As Integer
Static numStatic As Integer
'
Dim i As Integer
For i = 1 To 10
' incrementamos las variables
numDim += 1
numStatic += 1
Next
Console.WriteLine("El valor de numDim = {0}, " & _
"el valor de numStatic = {1}", _
numDim, numStatic)
End Sub
End Module

Se puede comprobar, que el valor de la variable numStatic mantiene el valor entre distintas llamadas, (mostrando los valores 10, 20 y 30), mientras que el valor de la variable numDim siempre mostrará 10.
Observar también, que en el procedimiento Main tenemos una variable llamada "i", esta variable al ser "local" al procedimiento no tendrá nada que ver con la variable "i" declarada en el procedimiento Prueba.

Las variables declaradas en los "bloques"

En los bloques podemos declarar variables "privadas" a esos bloques, pero en esta ocasión sólo pueden declararse con Dim.
Las variables declaradas en un bloque sólo serán visibles "dentro" de ese bloque, por tanto no podrán ser accedidas desde fuera del bloque.
Una variable declarada en un bloque sí se puede llamar como otra declarada a nivel de módulo, en ese caso, la variable "local" ocultará a la declarada a nivel de módulo.
Lo que debemos tener presente es que las variables declaradas en un bloque "mantienen" el valor mientras dure la vida del procedimiento (if,for,do,while),en el que se encuentran. Es como si fuesen "estáticas" mientras dure el procedimiento, aunque, cuando termina el procedimiento, ese valor se pierde.
También debemos saber que esto sólo es aplicable si no hemos asignado un valor a la variable al declararla, ya que si se asigna un valor al declararla, siempre usará ese valor.

EJEMPLO:
Module Modulo3
Sub Main()
Dim i As Integer
For i = 1 To 2
Console.WriteLine("Llamando a Prueba3, cuando i vale {0}", i)
Prueba3()
Next
End Sub
'
Sub Prueba3()
Dim i As Integer
For i = 1 To 5
If i > 1 Then
Dim j As Integer
Dim k As Integer = 2
'
' incrementamos las variables
k += 1
j += 1
Console.WriteLine("j = {0}, k = {1}", j, k)
End If
Next
End Sub
End Module

En este ejemplo, dentro del bloque If i > 1 Then... tenemos dos variables locales al bloque. La variable j se ha declarado de forma "normal", mientras que la variable k se ha declarado usando un valor inicial. Cada vez que llamemos al procedimiento Prueba3, el bucle se repetirá 5 veces y la condición para entrar en el bloque se ejecutará 4 de esas 5 veces, y como podemos comprobar la variable j va tomando valores desde 1 hasta 4, mientras que k siempre muestra el valor 3, (dos que le asignamos al declarar y uno del incremento).
La salida de esta prueba sería la siguiente:

Llamando a Prueba3, cuando i vale 1
j = 1, k = 3
j = 2, k = 3
j = 3, k = 3
j = 4, k = 3
Llamando a Prueba3, cuando i vale 2
j = 1, k = 3
j = 2, k = 3
j = 3, k = 3
j = 4, k = 3

En estos casos, lo recomendable sería declarar la variable j a nivel de procedimiento, ya que, además de que no podemos tener una variable que se llame j, nos aseguramos de que no nos "confundiremos" y podamos pensar que el valor que tendrá la variable será cero, que es lo que podría parecer.



Los niveles de visibilidad (accesibilidad o ámbito).

Veamos un resumen de los modificadores de visibilidad que podemos usar en los programas de Visual Basic .NET .
Modificador (VB) Descripción
Dim Declara una variable en un módulo, procedimiento o bloque.
Cuando se usa para declarar una variable a nivel de módulo, se puede sustituir por Private.
Private El elemento declarado sólo es visible dentro del nivel en el que se ha declarado.
Public El elemento es visible en cualquier parte.
Friend El elemento es visible dentro del propio ensamblado (proyecto).
Protected El elemento es visible sólo en las clases derivadas.
Protected Friend El elemento es visible en las clases derivadas y en el mismo ensamblado.
Hay que tener en cuenta que el ámbito que tendrán los elementos declarados, (por elemento entenderemos que es una variable, un procedimiento, una clase, módulo, estructura o una enumeración), dependerán del nivel en el que se encuentran. Por otro lado, si se declara un elemento como Private, será visible desde cualquier otro elemento que esté en el mismo nivel o en un nivel inferior.






Sobre el código y los datos de una clase.

Cómo maneja Visual Basic .NET y en general, todos los lenguajes de programación orientados a objeto , el código y los datos en memoria.
A lo que me refiero es a si existe "sobrecarga" (que el programa se sobrecargue en el sentido de que tenga más consumo de memoria/trabajo) cuando se utilizan varios objetos en la memoria.
Como sabemos cada vez que creamos, (instanciamos) un objeto en la memoria, estamos reservando espacio para ese objeto, la pregunta es:
¿Se reserva espacio tanto para los datos como para el código de los procedimientos?
La respuesta es que sí... se reserva espacio tanto para el código como para los datos, pero... el código siempre es el mismo para todos los objetos creados en la memoria, es decir, sólo existe una copia en la memoria del código, no se "copia" ese código una vez por cada objeto que hemos creado. Por otro lado, los datos si que ocupan espacios de memoria diferentes, uno para cada instancia.
No de ahora con el .NET, sino de antes... con el VB5, incluso, con el VB4.
Cuando se usa un procedimiento de una clase y en ese procedimiento se usan valores de instancia, (los que existen de forma independiente para cada objeto creado), el runtime realmente hace una llamada al "código" indicándole dónde están los datos que tiene que manipular, es decir, le pasa al código la dirección de memoria en la que se encuentran los datos a manipular, de esta forma, sólo existe una copia del código (igual que ocurre con los datos compartidos) y varias direcciones de memoria para los datos no compartidos, (según el número de instancias que se hayan creado).
Así que, a no preocuparse demasiado si el código contenido en un procedimiento es demasiado largo, ya que sólo existirá una vez en la memoria y no una vez por cada objeto creado.

Sobrecarga de procedimientos

La sobrecarga consiste en crear más de un procedimiento, constructor de instancias o propiedad en una clase con el mismo nombre y distintos tipos de argumento.
La sobrecarga es especialmente útil cuando un modelo de objeto exige el uso de nombres idénticos para procedimientos que operan en diferentes tipos de datos.
Es decir, que si necesitamos un procedimiento que utilice distinto número de parámetros o parámetros de distintos tipos, podemos usar la sobrecarga de procedimientos.
Sabiendo esto, podríamos hacer lo propio que con el procedimiento Prueba:
Prueba()
Prueba(ByVal uno As Integer)
Prueba(ByVal uno As Integer, ByVal dos As Integer)
Lo único es que no podríamos usar las formas 4 a 8. Pero esto no sería un inconveniente, ya que esas formas no son "lógicas" o intuitivas, como prefieras llamarlo.La pregunta que seguramente te harás (o deberías hacerte) es:
Si escribo tres procedimientos con diferente número de parámetros ¿debo repetir el código tres veces, uno para cada uno de los procedimientos?
La respuesta es: si o no... depende. Es decir, si quieres, puedes escribir tres veces o tres códigos distintos, uno para cada procedimiento. Pero si no quieres no...
muy bien, pero ¿cómo puedo hacer para que los tres procedimientos sean operativos sin tener que repetir prácticamente lo mismo en los tres procedimientos?
Imagínate que quieres que funcione como en el primer ejemplo, el que usaba los parámetros opcionales. Es decir, si no se indicaba uno de los parámetros tomara un valor por defecto.
Podríamos hacerlo de la siguiente forma:

Sub Prueba2()
' Si no se indica ninguno de los dos parámetros,
' usar los valores "por defecto"
Prueba2(3, 5)
End Sub
Sub Prueba2(ByVal uno As Integer)
' Si no se indica el segundo parámetro,
' usar el valor "por defecto"
Prueba2(uno, 5)
End Sub
Sub Prueba2(ByVal uno As Integer, ByVal dos As Integer)
Console.WriteLine("uno = {0}, dos = {1}", uno, dos)
Console.WriteLine()
End Sub

Es decir, si no se indica ningún parámetro, se usará la primera declaración, desde la que se llama a la tercera declaración que recibe los dos valores que nosotros queremos que tenga por defecto.
Si se usa la segunda declaración, se usará como primer valor el que se ha indicado y como segundo el predeterminado y luego se llama a la tercera declaración.
Y por último, si indicamos los dos parámetros se llamará directamente a la tercera declaración.

Nota:
Cuando se usan procedimientos sobrecargados, es el propio compilador de Visual Basic .NET el que decide cual es el procedimiento que mejor se adecua a los parámetros que se han indicado al llamar a ese procedimiento.
Constructores
Un Constructor es un método especial que se ejecuta durante la creación de un objeto. Todos los métodos constructores son procedimientos llamados New. Una clase puede tener cero, uno o más métodos constructores.
Si una clase tiene más de un método constructor lo que distingue un método constructor de otro es el tipo de dato y número de parámetros que lo define.

Sub New([parámetros])
sentencias
End Sub

Sobrecargar el constructor de las clases

Una de las utilidades más prácticas de la sobrecarga de procedimientos es sobrecargar el constructor de una clase.
El constructor de una clase es un procedimiento de tipo Sub llamado New, dicho procedimiento se ejecuta cada vez que creamos un nuevo objeto basado en una clase.
Si al declarar una clase no escribimos el "constructor", será el compilador de Visual Basic .NET el que se encargará de escribir uno genérico.
Esto es útil si queremos que al crear un objeto (o instancia) de una clase podamos hacerlo de varias formas, por ejemplo, sin indicar ningún parámetro o bien indicando algo que nuestra clase necesite a la hora de crear una nueva instancia de dicha clase.
Por ejemplo, si tenemos una clase llamada Cliente, puede sernos útil crear nuevos objetos indicando el nombre del cliente que contendrá dicha clase.
Veámoslo con un ejemplo:

Class Cliente
Public Nombre As String
Public email As String
'
Sub New()
'
End Sub

Sub New(ByVal elNombre As String)
Nombre = elNombre
End Sub
End Class
Esta clase nos permite crear nuevos objetos del tipo Cliente de dos formas.
Por ejemplo si tenemos una variable llamada cli, declarada de esta forma:
Dim cli As Cliente
podemos crear nuevas instancias sin indicar ningún parámetro:
cli = New Cliente()
o indicando un parámetro, el cual se asignará a la propiedad Nombre de la clase:
cli = New Cliente("AQUILES")
Ejemplo:
Public Class Class1
Public Nombre As String
Public email As String
'
Sub New()
'
End Sub

Sub New(ByVal elNombre As String)
Nombre = elNombre
End Sub
Public Property minombre() As String
Get
Return Nombre
End Get
Set(ByVal value As String)

End Set
End Property
End Class

Interfaz

Dim knom As New Class1("AQUILES")

Private Sub Button1_Click
If Len(knom.minombre) = 0 Then
Label1.Text = "vacio"
Else
Label1.Text = knom.minombre
End If End Sub