Hoy he encontrado un pequeño recurso en castellano, en las páginas de Codegear, y me ha parecido muy interesante. Se corresponde a una de las entradas existentes en su web, escritas por Andreano Lanuse y que habla de las ventajas de migrar desde delphi 7 a Delphi 2006. Andaba hace tiempo buscando un documento similar, que me sirviera de guión para ir compartiendo con vosotros su contenido. Y como siempre que encuentro algo interesante, quería compartirlo con vosotros:
http://dn.codegear.com/print/33963
Aunque el título hace referencia a Delphi 2006, se entiende que lo extendemos a Delphi 2007 para Win32. Y justamente buscaba algo así: un escrito no demasiado extenso, que pudiera reunir las últimas novedades que introduce el lenguaje, porque me había hecho el ánimo de hacer alguna entrada abordando dicho tema. No solo ya para ampliar el contenido del blog, sino para mi mismo, para tomar conciencia de que están y de que puedo llegar a usarlas. Eso sí. Debeis de tener en cuenta de que hay algunos cambios introducidos propios de Delphi 2007 que no se mencionan en dicho documento y que afectan a areas como la compatibilidad con Windosws Vista (¡recordad por poner un ejemplo, la disponibilidad de componentes diálogos propios de éste).
Y el caso, es que una gran parte de estas mejoras y cambios pueden pasarte inadvertidas fácilmente si no se hace uno el ánimo de ir incorporandolas a los recursos que uno habitualmente utiliza.
Me viene a la mente el caso de las clases anidadas…
Ya habeis podido leer en el artículo de Andreano Lanusse, que es uno de los cambios que nos van a permitir definir una subclase dentro de otra, quedando como el mismo nombre nos indica -anidada-. El tema se extiende tambien a las constantes, que van a poder anidarse dentro de la clase contenedora; lo que ellos llaman Nested Constants (Constantes anidadas)
Y la pregunta que se puede hacer un programador que lleve poco tiempo desarrollando con Delphi, es comprender que aporta esta novedad con respecto a las versiones anteriores… Tendríamos que hablar de ámbito y de visibilidad de las clases. Es decir, una clase anidada es accesible tan solo a través de la clase que la contiene, lo cual, permite cumplir compromisos de ocultación o encapsulación que no podían ser cumplidos desde las versiones anteriores, como Delphi 7. Si en una clase ibamos a necesitar los ambitos: private, protected, etc… a nivel de campos, por poner un ejemplo. Nos hacia falta otro recurso que nos permitiera extender este concepto a nivel de interfaz públlico. Dos clases definidas en el mismo módulo, en la sección de interfaz (interface) siempre se nos presentaban con un ambito global, desde fuera del módulo y eran accesibles por cualquier otra clase desde otro módulo distinto. Para ocultar una clase, nos obligabamos a definirla en la sección de implementación, que restringía el acceso a la misma desde clases ubicadas en otros módulos.
Vamos a imaginarnos un pequeño ejemplo mas rebuscado, que nos ponga en una tesitura similar…
Supogamos que tenemos un formulario de inicio de sesión, en el que pusimos un par de componentes que nos permitan editar el nombre de usuario y la contraseña y dos botones: uno para cancelar y otro para aceptar. Nuestro programador, por la razón que sea (¡quien conoce al alma humana!) se empeña en que sirva de base para otros formularios que redefinan su comportamiento. Es decir, que nuestro formulario que vemos en la imagen que figura mas abajo, no hace nada. Nada en absoluto. Lo haran sus descendientes… 🙂
unit uFormulario; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, Mask; type TFormulario = class(TForm) labUsuario: TLabel; labPassword: TLabel; ediUsuario: TEdit; mskPassword: TMaskEdit; btnOk: TBitBtn; btnCancel: TBitBtn; private { Private declarations } protected function MostrarFormulario: TModalResult; virtual; abstract; public { Public declarations } end; var Formulario: TFormulario; implementation {$R *.dfm} { TFormulario } end.
Pues bien… Veamos como podríamos plantearnos el tema desde la perspectiva de Delphi 7, si pretendieramos hacer uso de la herencia para redefinir su comportamiento en nuestra aplicacion. Podríamos optar a una solución como la que sigue.
unit umain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uFormulario; const MiSaludo = 'Bienvenido...'; type TInicioSesion = class(TFormulario) public function MostrarFormulario: TModalResult; override; end; TForm1 = class(TForm) private { Private declarations } MiFormulario: TInicioSesion; public { Public declarations } constructor Create(AOwner: TComponent); override; end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } constructor TForm1.Create(AOwner: TComponent); begin inherited; MiFormulario:= TInicioSesion.Create(Application); if MiFormulario.MostrarFormulario mrOk then Application.Terminate; end; function TInicioSesion.MostrarFormulario: TModalResult; begin Caption:= MiSaludo; Result:= ShowModal; end; end.
Sin embargo, la solución propuesta contiene un problema moral, que es la visibilidad de la clase TInicioSesion desde modulos externos de la misma aplicación. ¡Vamos! ¡Qué no es un problema técnico! Cuando digo moral me refiero exactamente a eso. Es como cuando programo en la empresa con mi compañero de trabajo, y hacemos uso del controlador de versiones Jedi VCS, cuando realmente lo tengo frente a mi mesa y podría saber en cualquier momento que módulos tiene abiertos, sin tener que consultar el interfaz de proyectos de Jedi. Aquí pasa algo parecido, puesto que soy yo el que decido en cualquier momento quien va a acceder a cada módulo, con independencia de su visibilidad.
Sin embargo, Delphi 2007 nos permite otra perspectiva que de forma natural resuelve nuestro problema moral. Veamos el planteamiento…
unit umain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uFormulario; type TForm1 = class(TForm) private { Private declarations } MiFormulario: TFormulario; const MiSaludo = 'Bienvenido...'; type TInicioSesion = class(TFormulario) public function MostrarFormulario: TModalResult; override; end; public { Public declarations } constructor Create(AOwner: TComponent); override; end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } constructor TForm1.Create(AOwner: TComponent); begin inherited; MiFormulario:= TInicioSesion.Create(Application); if (MiFormulario as TInicioSesion).MostrarFormulario mrOk then Application.Terminate; end; { TInicioSesion } function TForm1.TInicioSesion.MostrarFormulario: TModalResult; begin Caption:= MiSaludo; Result:= ShowModal; end; end.
Ambos códigos hacen exactamente lo mismo. La diferencia es el matiz de la visibilidad de la clase TInicioSesion, que cumple con mayor naturalidad los requisitos que nos demanda la programación orientada a objetos. Os dejo que lo reflexioneis y seguiremos hablando en esta y sucesivas entradas.
Ahh… un detalle mas para los que realmente se inician en Delphi… Hemos puesto:
MiFormulario:= TInicioSesion.Create(Application);
¿Piensas que hubiera funcionado «Application.CreateForm(TInicioSesion, MiFormulario);»?
¡Claro que no!… pero también es una buena reflexión pensar el por qué no. 😉
- Codigo fuente de la entrada:
Comentarios recientes