Material POO
Material POO
El presente capítulo expone los conceptos generales de la programación orientada a objetos (POO). Estos
conceptos están relacionados con los objetos en sí y con su relación con otros objetos. Todavía se habla
de la POO con entusiasmo, sobre todo cuando quien lo hace no ha programado con Lenguajes como C++
o Java. Es necesario destacar que hace mucho tiempo el tema dejó de ser una novedad, y. sin embargo,
por alguna extraña razón, se sigue viendo a dicho modelo de programación como "lo nuevo" (sobre todo
entre aquellos que nunca habían desarrollado en POO).
Quizá tenga mucho que ver que el lenguaje más utilizado en el mundo. Visual Basic en su versión 6, no
estaba orientado a objetos; cualquiera que programara en POO formaba parte de un grupo más reducido
y diferente, lo que concierne siempre un cierto grado de especialidad.
Hasta hace poco, un programador en C++ era más elogiado que un programador de Visual Basic, en gran
medida porque había menos programadores de C++ que de Visual Basic (simple economía: a menor
oferta, mayor el precio). Ahora las cosas están cambiando, ya que Visual Basic se integra al mundo POO,
toma de sí mismo la simplicidad de su código. y adopta de la plataforma .NET capacidades que eliminan
las limitaciones que interiormente tenía, ganando flexibilidad y potencia, y cubriendo aspectos que antes
eran más sencillos en otros lenguajes como C++.
Si se pregunta qué es mejor, el enfoque de procedimientos, el de eventos o el orientado a objetos, la
respuesta es contundente; depende de lo que se quiera hacer. Hay cosas más sencillas de implementar en
una orientación que en otra, así que no se sienta mal por no haber aprendido a programar en POO con
anterioridad. Quizá no lo haya necesitado.
Aunque la experiencia previa en programación es muy útil al aprender POO, no todo el que programa
Visual Básico.
Podrá programar en Visual Basic sin modificar algunos paradigmas. Es importante, por no decir que
indispensable, comprender el marco teórico del modelo orientado a objetos para ser un buen programador
en POO.
Encapsulamiento (encapsulation)
Para que una aplicación realmente este" orientada a objetos debe admitir las cualidades de
encapsulamiento, herencia y polimorfismo. Estas (res cualidades son representativas de POO).
El encapsulamiento es la capacidad que tiene un objeto para almacenar datos y procedimientos, como una
unidad funcional, y permitir el acceso a ellos sin que los demás objetos tengan la necesidad de conocer
cómo se integran dichos datos y dicho comportamiento dentro del objeto.
Usted ya sabe que los objetos se hacen peticiones entre sí a través de mensajes, y que un objeto puede
hacer uso de otros objetos. Imagine que un objeto (objeto A) realiza un cálculo financiero complejo.
Imagine que otro objeto (objeto B) realiza un cálculo que determina el monto de los gastos de la compañía
en un periodo determinado.
Resulta que el objeto A, para desarrollar sus operaciones, necesita la información que produce el objeto B,
y para obtener dicha información se comunica con B enviando un mensaje (mensaje X).
Como respuesta, el objeto B le envía al objeto A la contestación a través de un mensaje (mensaje Y).
La persona que desarrolló el objeto B se da cuenta de que el cálculo que realiza el objeto puede mejorarse.
Procede a cambiar el código (comportamiento), haciéndolo más eficiente, reduciendo el tiempo de
respuesta a la mitad.
Como consecuencia del encapsulamiento, el objeto A no necesita saber qué hace el objeto B para
proporcionar la información que se le pide. El encapsulamiento permite que el estado o el comportamiento
de un objeto puedan modificarse para darle mayor o mejor funcionalidad al objeto, sin afectar a otros
objetos asociados. El objeto A sigue enviando el mensaje X al objeto B, y el objeto B le sigue respondiendo
con el mensaje Y, sólo que en la mitad del tiempo que antes.
El encapsulamiento sólo debe respetar una regla: al modificar un objeto, éste debe seguir aceptando los
mismos mensajes de petición, y enviando los mismos mensajes de respuesta. Fuera de eso, el objeto
puede ser una caja negra para los demás desarrolladores, sin que ello perjudique la funcionalidad de la
aplicación.
Las ventajas que proporciona el encapsulamiento a los programadores son las siguientes:
Herencia (inheritance)
La herencia describe la capacidad de crear una nueva clase basada en una existente.
La clase a partir de la cual se generará la nueva recibe el nombre de clase base (base class); la nueva
clase, llamada clase derivada (deríved class), hereda todas las propiedades, métodos y eventos de la clase
base y a partir de ahí, es posible agregarle las propiedades y métodos particulares que la hacen especial.
Un ejemplo puede aclararnos las cosas. Imagine que crea una clase llamada Vehículo Automotor. Esta
clase contendrá propiedades que todos los vehículos automotores tienen como son color, tipo de
transmisión, tipo de combustible, etcétera. Además, tendrá definidos los métodos aplicables para lodos los
vehículos automotores; por ejemplo, encender o apagar el motor.
Hay un tipo de vehículos automotores que sirven para carga de materiales (vehículo de carga); en ellos, la
capacidad de carga en toneladas, las dimensiones máximas de la carga y la necesidad de refrigeración de
la carga son importantes, pero, ¿son esos datos importantes para un vehículo que sólo es utilizado para
transportar personas? La respuesta es que no.
Tenemos las siguientes alternativas de solución para manejar la información del ejemplo:
Definir la clase VehículoAutoMotor con todas las características posibles para todos los vehículos
automotores posibles; eso sobrecargaría a la clase de muchas propiedades no aplicables para todos los
vehículos, complicando el trabajo de afirmar o negar las características aplicables a un vehículo en
particular. En realidad, todo está siendo manejado en un mismo objeto, tal y como sería en una
programación procedural,
• Definir una clase independiente de VehículoAutoMotor; por ejemplo, VehículoAutoMotorCarga, que
contenga todas las propiedades y los métodos que requieren ser especificadas para un vehículo
automotor de carga. Obviamente, muchas de las características de los vehículos automotores de carga
son comunes para todos los vehículos automotores. Eso implicaría una doble codificación (codificación
redundante), que revela que, no obstante que ya teníamos codificados los pormenores de los vehículos
automotores, no reutilizamos dicho código, pues creamos uno enteramente nuevo. En esta alternativa
tampoco funciona la herencia.
• Definir una clase independiente, por ejemplo VeniculoAutoMotorCarga, que contenga sólo aquellas
propiedades y métodos no definidos en VehiculoAutoMotor. La nueva clase (VehículoAutoMotorCarga)
se generaría a partir de una clase base (VehículoAutoMotor), aprovechando toda su codificación. Esta
alternativa implica un uso funcional de la herencia, en donde se tiene una clase base y una clase
derivada.
Las ventajas que proporciona la herencia para los programadores de software son las siguientes:
• Reuso de código. La mayor ventaja de la herencia es que el código se reutiliza de una forma más
eficiente. pues las clases parten de otras clases más generales; esto garantiza que de inicio las
clases ya tienen la funcionalidad de otras anteriormente creadas. Sólo se estará desarrollando
nueva funcionalidad, evitándose el código redundante.
• Jerarquía de clases. Es posible realizar una jerarquía que distinga procesos generales y
específicos.
La figura 9.2 muestra de manera conceptual cómo, a partir de una clase base, surgen clases
derivadas que pueden disponer de todas las propiedades, métodos y eventos de la clase base, y
que además incluyen las características particulares de aquello que no es posible representar
usando solamente lo definido en la clase base. En la jerarquía de clases, la clase base no requiere
de las clases derivadas, pero las clases derivadas sí requieren de lo definido en la clase base.
Polimorfismo (polymorphism)
El polimorfismo es la capacidad de manejar múltiples clases que pueden ser utilizadas de manera
intercambiable a través de una misma implementación (nombre de clase). El polimorfismo es esencial para
la programación orientada a objetos, ya que permite, a través de un mismo nombre de clase, agrupar
diferentes funcionalidades, dependiendo de las propiedades y métodos que se utilicen al momento de
invocarlas.
NOTA
En Visual Studio puede verse claramente esta capacidad. Si en alguno de sus
programas utiliza, por citar un ejemplo, la función Val, que convierte a número una
expresión, aparecerá una referencia como sigue:
Val(|
» 1 of 3 r Val (InputStr As String) AsDouble InputStr: Any valid String
expression,
Imagine que tiene una aplicación que controla las ventas de un negocio. Puede ser que tenga un objeto
llamado RegistraVenta, que se encargue de almacenar en una base de datos los pormenores de la venta.
Suponga que hay un objeto llamado ActualizaLineacrédito que se encarga de actualizar la línea de crédito
de los clientes que compran en el establecimiento; como ha de suponer, las acciones que realizará
ActualizaLíneaCrédito tienen que ver si la compra se realiza u crédito o de contado. En enfoque procedural,
sería necesario hacer dos procedimientos distintos, de diferente nombre, para controlar cada una de las
alternativas.
En POO se pueden generar dos clases distintas, que contengan cada una de las alternativas de la
actualización de la línea de crédito; la diferencia estriba en que para el programa sólo existirá una. Será la
misma plataforma de ejecución la que determine, con base en los datos proporcionados, qué clase es la
que se empleará.
Overloading, Overriding y Shadowing
Para implementar el polimorfismo, hay que conocer tres conceptos básicos: Overloading, Overriding y
Shadowing, Al explicar el polimorfismo, concluimos que un mismo nombre de método puede tener
funcionalidad distinta dependiendo de los argumentos que le son proporcionados.
Como sabe, los argumentos van entre paréntesis y separados por comas, después del nombre del método
o función; por tratarse de una lista de valores, estamos ante la presencia de una serie de valores.
NOTA
La implementación en programación de la terminología descrita en este capítulo se demostrará en el
capítulo siguiente.
Los miembros con característica Overloaded son utilizados para proporcionar diferentes versiones de una
propiedad o método que tiene el mismo nombre, pero que acepta diferente número de argumentos, o
argumentos de diferente tipo de dato.
Las propiedades y métodos con característica Overriden son utilizados para reemplazaría propiedad o
método que, habiendo sido heredado de una clase base, no es lo apropiado para la clase derivada. Esto
permite sustituir elementos heredados de la clase base, con aquellos que la clase derivada realmente
necesita.
La única restricción que se tiene es que los miembros Overriden deben aceptar el mismo número de
argumentos y devolver los mismos valores, respetando los tipos de datos de la clase base, a efecto de que
el encapsulamiento de los objetos sea posible.
Los miembros con característica Shadowed son aquellos que reemplazan localmente a otros miembros
existentes, dentro de un alcance diferente al original.
Estado
El estado de un objeto es la situación de forma y comportamiento que tiene el objeto en un momento
determinado en tiempo de ejecución.
El estado está determinado por el juego de valores que tienen sus propiedades. Como sabemos, las
propiedades son las características particulares del objeto y especifican su nombre, posición, apariencia y
hasta sus capacidades de interacción con el usuario y otros objetos.
Un objeto puede estar disponible o no para su uso en una interfaz (Enabled=True o Enabled=False); puede
tener un ancho de 10 o 20píxeles (Width=10 o Width=20). Si cambiamos el valor de cualquiera de las
propiedades, como podría ser incrementar el ancho del objeto de 10 a 20 píseles, ello représenla una
modificación de es leído.
La figura 9.3 nos invita a imaginar el núcleo de un objeto como un conjunto de propiedades establecidas;
vea cómo la identidad del objeto también forma parte del estado del mismo, pues Ñame es una propiedad,
al igual que las de posición, apariencia y otras.
Figura 9.3 Estado y Comportamiento
Comportamiento
El comportamiento es la capacidad del objeto para funcionar de una determinada manera. Como respuesta
a la interacción del usuario, de otros objetos, o incluso del mismo sistema operativo, el objeto podrá
comportarse de diferente forma.
El comportamiento de un objeto se presenta por la posibilidad de mandar llamar a ejecución:
• Los métodos
• Los procedimientos de evento
• Los procedimientos y funciones definidas por el usuario
Los métodos, como sabe, son los comportamientos predefinidos que un objeto puede presentar, y que se
encuentran definidos por la clase de la cual el objeto deriva.
Los procedimientos de evento son aquellos procedimientos que le suceden a un objeto como respuesta a la
interacción que tienen con el usuario u otros objetos. El objeto tiene un conjunto de eventos que reconoce, y
usted como desarrollador lo único que hace es decirle a su programa a) que quiere que un objeto
determinado sea sensible a los eventos que le sucedan (especificación WithEvents al momento de la
declaración), b) elaborar un procedimiento y c) especificarle a dicho procedimiento que será ejecutado en
caso de que le suceda el evento a alguno de los objetos que maneje (handles).
En versiones anteriores de Visual Basic, un procedimiento de evento podía servir sólo para manejar las
acciones que deberían suceder cuando a un objeto determinado le sucedía un evento determinado; de
hecho, el nombre de los procedimientos de evento estaba formado por el nombre del objeto y el nombre de
evento, separados por un guión bajo. Había controles para los cuales se aplicaban las mismas validaciones
(por ejemplo, que los cuadros de texto no se dejaran vacíos); no obstante que el proceso a realizar era el
mismo para todos los cuadros de texto, a cada uno de ellos se le debía definir un procedimiento de evento.
Algunas cosas cambiaron en Visual Basic. Un procedimiento de evento puede manejar un mismo evento
para uno o más objetos; por ese motivo, el nombre asociado a un solo objeto y un solo evento ya no tiene
sentido. Ahora el nombre del procedimiento de evento puede ser el que sea.
La única cosa que debemos respetar son los argumentos implícitos. Los procedimientos pueden admitir
argumentos; con base en ellos es posible modificar el resultado del procesamiento o el valor que devuelven
(en el caso de las funciones). Los argumentos implícitos son aquellos que son declarados por Visual Basic
de manera automática; en la declaración de este tipo de argumentos el programador no participa más que
como espectador y usuario.
Cada evento podrá exigir la presencia de los argumentos implícitos que necesita para trabajar; cuando
nosotros declaramos un objeto especificando que queremos que sea sensible a eventos (WithEvents),
también le estamos diciendo al programa que queremos que Visual Basic se encargue de actualizar, en
tiempo de ejecución, los datos de los argumentos implícitos de cada uno de los eventos aplicables al objeto.
Nosotros no determinamos el valor que tendrán los argumentos implícitos; es el CLR, en tiempo de
ejecución, el que determina qué valores tendrán.
Los procedimientos definidos por el usuario y las funciones definidas por el usuario, son los procedimientos
y funciones que usted codifica; no dependen de los eventos que pueden sucederle al objeto, ni requieren
estar predefinidos en ninguna clase: son la forma más pura de codificación. Hace muchos años, cuando
nadie hablaba aún de objetos ni de eventos, los procedimientos y funciones definidos por el usuario ya
existían.
NOTA
Algunos desarrolladores, para no estar preocupándose respecto a qué objetos permitirán manejo de
eventos y cuáles no, colocan la especificación WithÉvents a todos los objetos. Aunque es una forma
simple de quitarse problemas, no es lo más estructurado; deja ver que el programador no conoce a
profundidad el comportamiento que tendrá su interfaz. Sugerimos, colocar WithÉvents sólo a los objetos
que realmente manejarán procedimientos de eventos.