3 de julio de 2017

¿Donde se encuentra el control?

Artículo original: Where is that control?
http://www.jamesbooth.com/containership.htm
Autor: Jim Booth
Traducción: José Luis Santana Blasco


Contenedores, todos hemos oído esta palabra. “Visual FoxPro tiene un modelo de contenedores muy bueno.” ¿Qué son los contenedores y porque nos tenemos que preocupar por ellos? Por un parte, trabajamos con Visual FoxPro y por tanto necesitamos hacer uso de los contenedores de VFP, pero se pueden dar más razones por las que deberíamos conocer mejor los contenedores. El uso de los contenedores en nuestro beneficio nos permitirá crear clases más reutilizables y flexibles.

Contenedores y  POO

El concepto de contenedores no es nuevo en la Programación Orientada a Objetos. Uno de los diagramas empleado para diseñar sistemas OO se llama Diagrama Todo/Parte. Este diagrama describe objetos que están compuestos de otros objetos. Por ejemplo, un Formulario de entrada de datos contiene un gran número de controles, algunos de estos controles pueden encontrarse agrupados dentro de algún tipo de contenedor, etc.

Los contenedores necesitan que se indique el objeto donde "viven".  Esto no se diferencia de enviar una carta a alguien, en VFP se debe indicar  donde se encuentra el objeto que queremos emplear. Si quisieran enviarme una carta, no pueden  remitirla a Jim Booth sin más indicaciones. El cartero no podrá encontrarme así. Necesitarán decirle al cartero que vivo en un país llamado USA, en un estado llamado Connecticut, en una ciudad llamada Prospect, en una calle llamada Birchwood Terrace, en la casa numero 1, y que mi nombre es Jim Booth. En VFP la sintaxis sería algo así:

USA.Connecticut.Prospect.BirchwoodTerrace.One.JimBooth

Debemos localizar los objetos de VFP de la misma manera, mediante su referencia dentro de su ámbito de actuación. Un cuadro de texto llamado Text1 que se encuentre en un formulario llamado Form1 se referencia como Form1.Text1. Coloca este cuadro de texto en la página 1 de un marco de página en Form1 y su referencia será entonces Form1.PageFrame1.Page1.Text1. Esta es la referencia al contenedor que VFP necesita.

Podemos pensar en este comportamiento como si estuviésemos refiriéndonos a cajas. El formulario es una caja que contiene cosas, dentro de la caja formulario hay una caja Marco de página que contiene únicamente unas cosas llamadas páginas, y en una de estas cajas páginas hay un cuadro de texto que es a lo que queremos hacer referencia. Entonces, le decimos a VFP que mire dentro de la caja formulario una caja marco de página llamada Pageframe1, y que en esta caja PageFrame1 debe buscar una caja página llamada page1 y que a su vez busque dentro de la caja Page1 algo llamado text1.

Comprendiendo el modelo de contenedores de VFP

Visual FoxPro tiene un numero de clases base que son  originalmente contenedores, esto es, que pueden contener otros objetos. Estas clases contenedoras son: Conjunto de Formularios, Formulario, Contenedor, Custom, Control, Cuadricula, Marcos de Página, Página y Columna (se debe tener cuidado de no confundir la clase Contenedor con la habilidad de una clase de ser un contenedor).

Estas clases base pueden ser empleadas para proveer una aproximación a lo que en diseño Orientado a Objetos se conoce como composición. Composición es la combinación de un número de objetos dentro de otro objeto más complejo. La composición se puede realizar de dos maneras: temprana o tardía.

La composición temprana se produce cuando se construye el objeto y posteriormente se le da comportamiento a los miembros que forman la composición. La composición tardía se diferencia de la temprana en que cada clase individual tiene completamente definido todo su comportamiento antes de combinarse en el contenedor. En conveniente seguir una estrategia de diseño basada en  la composición tardía. 

Como ejemplo, consideremos una entrada de datos de una dirección. Esta clase compuesta se puede construir mediante un cuadro de texto para el nombre, dos cuadros de texto para la dirección de la calle, uno más para la ciudad, el estado, y el código postal. Todos estos cuadros de texto se colocan en una clase contenedor para emplearlos como si fuesen un solo objeto. ¿Cual es el beneficio de crear esta clase? El más obvio es la reutilización, en cada formulario de una aplicación que necesite una dirección simplemente pondremos nuestro objeto dirección en el formulario y con esto tendremos todo el trabajo hecho.

Comparemos ahora  la composición temprana en contraposición a la composición tardía. En la composición temprana podemos construir la clase contenedora con los cuadros de texto, y entonces escribir código dentro de varios cuadros de texto para darle el comportamiento. Posiblemente escribamos código dentro de los Valid de los cuadros de texto de Estado y de Código Postal para validar la entrada de estados de USA y el dato del Código Postal. En la composición tardía, definiremos los cuadros de texto de Estado y de Código Postal como clases independientes, y posteriormente combinaremos estas con los otros cuadros de texto en el contenedor.

¿Cual es la diferencia entre los dos métodos? Las diferencias se ven cuando deseamos modificar el comportamiento de la clase dirección. Supongamos que necesita crear una dirección internacional. Con la clase realizada mediante composición temprana, podemos realizar una subclase de la dirección y entonces intentar alterar el comportamiento de los objetos contenidos. Esto es bastante fácil, siempre y cuando queramos conservar todos los controles pero, si se quiere eliminar los cuadros de texto de la dirección, y reemplazar estos por un cuadro de edición nos encontraremos con una sorpresa. Visual FoxPro no permite eliminar ninguno de los cuadros de texto porque son miembros de la clase padre, por tanto la única opción es hacer los cuadros de texto invisibles o construir una nueva clase dirección. Si se escogemos esto último tendremos que rescribir el código de comportamiento para todos los cuadros de texto que deseemos conservar ya que ese comportamiento se define en la clase contenedor y no en los cuadros de texto.

Con composición tardía simplemente realizaremos una nueva clase dirección y pondremos dentro lo que queramos. Dado que la definición del comportamiento de cada cuadro de texto se encuentra en su propia clase, incorporaremos los que queramos y dejaremos fuera aquellos que no necesitemos.

Escribiendo código en contenedores

Bien, hemos visto los beneficios de los contenedores y de la composición pero, ¿cómo se relaciona nuestro código con los contenedores?. Antes hemos visto que necesitamos emplear la jerarquía del contenedor para referenciar en tiempo de ejecución los objetos que se encuentran dentro de él, sin embargo, hay más de una forma de referenciar un objeto, y unas son mejores que otras.

Por ejemplo, mire el formulario de la figura 1.

Figura 1 un formulario con varios niveles de contenedores.

Este formulario tiene dos instancias de una clase contenedora que contiene un cuadro de texto y un botón de comando. La primera instancia se encuentra en Page1 del marco de página  exterior (contenedor 1), la segunda se encuentra en la Page1 dentro del marco de página interior (contenedor 2). El comportamiento programado en el botón de comando hace que cambie el valor de su respectivo cuadro de texto para hacerlo coincidir con el título del botón.

Una solución para esto, en el contenedor 2, es escribir el siguiente código: 

ThisForm.PageFrame1.Page1.PageFrame1.Page1.Container1.Text1.Value = “ABC”

Hemos Empleado la referencia absoluta del control dentro del contenedor. Sin embargo, si se emplea este código y el contenedor 1 se crea copiando desde el contenedor 2 y pegándolo en la otra página, ¿qué comportamiento podemos esperar al pulsar el botón que se encuentra en el contenedor 1? El botón del contenedor 1 cambiará el cuadro de texto en el contenedor 2, dado que la referencia es absoluta.

En vez de programarlo así, podemos emplear referencia relativa para el código del botón:

This.Parent.Text1.Value = “ABC”

Ahora ambos botones referencian el cuadro de texto asociado con él dentro del mismo contenedor. Un diseño mejor sería programar en el contenedor un método para la actualización de los controles y hacer que el botón llame a este método (patrón mediador). ¿ Por qué es mejor el patrón mediador?, porque ahora podremos cambiar el nombre del cuadro de texto y solo necesitaremos corregir el código en el contenedor, el botón no se tendrá que preocupar más por el nombre del cuadro de texto. No solo eso, podremos añadir más controles al contenedor y hacer que el botón actúe sobre todos ellos sin modificar el código del botón.

Algunas Definiciones

En las secciones anteriores se han introducido algunos componentes sintácticos que podrían ser nuevos para alguien.  Os proporciono algunas definiciones.

Término                    Definición

THIS

Una referencia al objeto que contiene el código.

THISFORM

Una referencia al formulario que contiene el código, incluso si el código se encuentra dentro de un objeto contenido en el formulario.

THISFORMSET

Una referencia al conjunto de formularios que contiene el código, incluso si el código se encuentra dentro de un objeto contenido en el formulario o en un formulario contenido en el conjunto de formularios.

Parent

Una referencia al contenedor inmediato superior del objeto que contiene el código. Parent puede ser combinado para ir hacia atrás en el árbol de contenedores, así si un cuadro de texto se encuentra en una página de un marco de página de un formulario, This.parent.Parent.Parent hace referencia al formulario.

ActiveX y Controles OLE

Se han dado un gran número de comunicaciones indicando que el nuevo control Calendar 8.0 no funciona correctamente. La gente que alertó  de esto, intentaba establecer o leer el valor de una propiedad del Control calendario, y recibió un mensaje de error equivocado que les indicó que la propiedad no existía.

Para comprender la razón de este error y la forma de no obtenerlo es importante comprender el contenedor de controles ActiveX de Visual FoxPro. VFP emplea el Control OLE como contenedor de los controles ActiveX. El control calendario se encuentra actualmente dentro de un Control OLE. Para referenciar el control contenido se debe emplear la propiedad Object del Control OLE. Esta propiedad es una referencia al objeto que se encuentra contenido dentro del Control OLE. Las siguientes dos lineas de código explican lo que significa aquí:

ThisForm.OLEControl1.Value = {^1999/01/01} && produce un error

ThisForm.OLEControl1.Object.Value = {^1999/01/01} && no produce error

Aparentemente, VFP se confunde con la propiedad llamada Value, debido a que el Control OLE no la tiene y por tanto VFP informa con un error. Normalmente solo necesitas emplear la propiedad Object cuando ambos, el objeto contenido y el Control OLE comparten propiedades con el mismo nombre. Mi experiencia es que se tiene menos problemas si siempre se emplea la propiedad Object cuando se referencia al objeto que se encuentra dentro del Control OLE.

Sumario

En este artículo únicamente se han tratado las nociones básicas del tema de los contenedores en Visual FoxPro. Es un tema que podría ocupar un libro entero. Se ha comentado los aspectos principales de los contenedores y como les afecta a nuestro código y a nuestros sistemas. Ha visto como sacarle el máximo provecho al modelo de contenedores de Visual FoxPro en su trabajo y como evitar problemas que pueden venir de una mala comprensión de la forma de trabajo de los contenedores.

No hay comentarios. :

Publicar un comentario