Curioseando…

mayo 29, 2009 en Delphi, Enlace interesante, Entrada Diario, Noticias, Noticias Delphi

Os confieso que no se si me acaba de gustar eso de los Twibes… No podría ni decir que sí ni decir que no… Llevo varios días siguiendo los comentarios y resulta un tanto… ummmmm… no se calificarlo. :-)  ¿Es eso que llaman microblogging y que está tan de moda, no?. Yo es que en esas cosas soy un tanto raro, porque gracias a Dios cada uno es como es y tiene sus gustos y eso hace la vida mas hermosa. Util, Sí. Puede llegar a serlo. De hecho esta noche he podido recoger  rebuscando en los comentarios varios enlaces interesantes. 

Cariñosamente unos dirían que es como una gran sala donde uno escucha los cotilleos que quiere. Hay corrillos, y te acercas a uno y escuchas: Bla, bla bla… (con un maximo de 14o palabras :-) ). Te acercas a otro y lo mismo.

Hablan de sus cosas. El grupo principal de Delphi tiene un ligero movimiento (un leve soplo en una noche de verano).  Y yo me siento un tanto ajeno, extraño. La palabra apropiada quizas fuera incómodo, como cuando vas a una reunión en donde no conoces a nadie y nadie te advierte ni para bien ni para mal. :-) Pero tiene una cosa buena y es que algunos de los comentarios que pueden pasar inadvertidos a primera vista, aportan bastante mas información de la que en principio se podría esperar.

Algun comentario me llevó a:

http://www.drbob42.com/Weaver/index.htm

De allí a:

http://picasaweb.google.com/LovePhotoStore/DelphiLive2009?feat=directlink#5336279495648421170

y de ese enlace a:

http://docs.embarcadero.com/products/rad_studio/books/GetStartDelphiC++2009.pdf

El primero me daba unas pinceladas sobre el proxima versión de Delphi. La segunda más de un centenar de instantaneas de las sesiones de DelphiLive. Y la ultima, una guía con 76 páginas publicada por Embarcadero, acerca de los primeros pasos con Delphi 2009 y C++2009. En Lulu.com existe una versión impresa de esta guia de primeros pasos en los dos entornos.

No se como lo veis vosotros. A nuestro alrededor todo transcurre con extrema rapidez. Nos queda la sensación de que todos se han vuelto un poco locos y resulta dificil asimilar la decena de nombres nuevos que surgen mes a mes. ¿Quien dijo que estabamos en la versión quinta de SHME? ¿Qué ya no existe porque fue superada por HPTVVss@? Dios mío… Si tenia precisamente un articulo sobre SHME|33 y no me ha dado tiempo ni siquiera a acabarlo?

:-D

Es decir, que uno debería de cuando en cuando encerrarse en su cuarto o en su despacho, sin internet, sin móvil y sin televisión. Con una radio de esas, de las de siempre, de esas del dial, y escuchar buena música mientras acabas a tiempo el proyecto que llevas a medias. Demasiado ruido en el ambiente. Demasiado ruido.

Y respecto al grupo de Delphi Español, aumentó su cantidad de miembros a cinco, a base de insistir a mi amigo Manuel a que se apuntase. :-)   ¿Donde estais?  Hace un frío de muerte en ese engendro virtual. Esperaba que el número fuera creciendo y fueramos al menos seis o siete…   ;-)  

De momento, creo que están encontrando un buena utilidad al recoger las novedades del entorno. Ya sabeis que yo no tiro nunca la toalla.

Experimentos, reflexiones y otros artefactos (III)

mayo 24, 2009 en Artículos, Código, Delphi, Entrada Diario, Taller práctico

Nuestro primer experimento...

Nuestro primer experimento...

Como reza esa primera imagen que abre el post, es un buen momento para intentar razonar en terminos de clases, y experimentar con el ejemplo que intentabamos abordar y que nos servía para reflexionar. En él, podríamos capturar la idea de atributo, como ya se ha podido extraer de las dos entradas anteriores, consistía en un rasgo diferenciador que combinado con otros, nos servía para identificar un artículo determinado. Podemos convenir aceptar la clase TAtributo  como una representación de ese rasgo.

Y siguiendo con ese razonamiento, también parece que se desprende de la misma existencia de ese atributo, la idea de que va a depender de otra entidad que sea capaz de gestionarlos, ya que será necesaria la existencia de uno o mas atributos y por lo tanto, necesitamos ”algo” que sea capaz de operar con ellos y relacionarlos. A esta clase, le podríamos llamar TGenerador, por buscar un nombre que resulte familiar a esa idea de “artefacto” que va a mostrar las distintas combinaciones de codigo posibles para formar nuestro artículo.

¿Qué os parece si empezamos a trabajar?

Vamos a resumir lo que tenemos hasta ahora. Partimos de esas dos ideas: TGenerador y TAtributo. Podemos empezar a perfilarlas, con dos operaciones básicas, como pueden ser:

* Añadir un atributo y

* Cambiar la posición de dos de ellos.

Vamos a escribir unas lineas de código y un pequeño ejemplo que las ponga en práctica, para cercionarnos de que  los razonamientos son correctos.  Para poder diferenciar los atributos en nuestro interfaz de prueba, hemos implementado la propiedad captión que nos permite visualizarlos de forma sencilla dentro de un listbox.

 

unit UPensarEnClases;

interface

uses
 SysUtils, Classes;
type

  TAtributo = class;

  TGenerador = class(TObject)
  private
    FAtributos: TList;
    function GetAtributos(Indice: Integer): TAtributo;
  protected
  public
    constructor Create;
    destructor Destroy; override;
    function AddAtributo: TAtributo;
    function Count: Integer;
    procedure SetUpPosition(AAtributo: TAtributo);
    procedure SetDownPosition(AAtributo: TAtributo);
    function GetPosicion(AAtributo: TAtributo): Integer;
    property Atributos[Indice: Integer]: TAtributo read GetAtributos;
  end;

  TAtributo = class(TObject)
  private
    FGenerador: TGenerador;
    FCaption: String;
    procedure SetCaption(const Value: String);
  protected
  public
    function GetPosicion: Integer;
    constructor Create(AGenerador: TGenerador); virtual;
    destructor Destroy; override;
    property Caption: String read FCaption write SetCaption;
  end;

implementation

{ TAtributo }

constructor TAtributo.Create(AGenerador: TGenerador);
begin
  if not Assigned(AGenerador)  then
     Raise Exception.Create('Error: Referencia al generador no valida');
   FGenerador:= AGenerador;
end;

destructor TAtributo.Destroy;
begin
  FGenerador:= Nil;
  inherited;
end;

function TAtributo.GetPosicion: Integer;
begin
  Result:= FGenerador.GetPosicion(Self);
end;

procedure TAtributo.SetCaption(const Value: String);
begin
  FCaption := Value;
end;

{ TGenerador }

function TGenerador.AddAtributo: TAtributo;
begin
   Result:= TAtributo.Create(Self);
   FAtributos.Add(Result);
end;

function TGenerador.Count: Integer;
begin
   Result:= FAtributos.Count;
end;

constructor TGenerador.Create;
begin
  FAtributos:= TList.Create;
end;

destructor TGenerador.Destroy;
var
 i: Integer;
 f: TAtributo;
begin
  for i:= 0 to Count - 1 do begin
    f:= TAtributo(FAtributos[i]);
    FreeAndNil(f);
  end;
  FAtributos.Clear;
  FreeAndNil(FAtributos);
  inherited;
end;

function TGenerador.GetAtributos(Indice: Integer): TAtributo;
begin
   if (Indice < 0) or (Indice > FAtributos.Count-1)then
     Raise Exception.Create('Error indice get fuera de rango');
   Result:= FAtributos[Indice];
end;

function TGenerador.GetPosicion(AAtributo: TAtributo): Integer;
begin
   Result:= FAtributos.IndexOf(AAtributo);
end;

procedure TGenerador.SetDownPosition(AAtributo: TAtributo);
var
  i: Integer;
begin
   i:= FAtributos.IndexOf(AAtributo);
   if (i < Count -1) then FAtributos.Exchange(i, i+1);
end;

procedure TGenerador.SetUpPosition(AAtributo: TAtributo);
var
  i: Integer;
begin
   i:= FAtributos.IndexOf(AAtributo);
   if (i > 0) then FAtributos.Exchange(i, i-1);
end;

end.

Finalmente, vamos a ver el pequeño formulario que nos permite verificar que nuestro interfaz e implementación hacen lo que le hemos solicitado.

Al ser creado el formulario, crearemos el generador y añadiremos los atributos (3)  y daremos la oportunidad a nuestro usuario de que los cambie de posición de los mismos.

Es muy sencillo… upsssss…  (aquí tenéis)

 

unit UMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, uPensarEnClases;

type
  TfrmPensarEnClases = class(TForm)
    lbxAtributos: TListBox;
    btnSubir: TButton;
    btnBajar: TButton;
    Label1: TLabel;
    procedure btnSubirClick(Sender: TObject);
    procedure btnBajarClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure ActualizarInterfaz;
  public
    { Public declarations }
    FGenerador: TGenerador;
  end;

var
  frmPensarEnClases: TfrmPensarEnClases;

implementation

{$R *.dfm}

procedure TfrmPensarEnClases.ActualizarInterfaz;
var
  i: Integer;
begin
   lbxAtributos.Clear;
   for i := 0 to FGenerador.Count - 1 do
      lbxAtributos.Items.Add(FGenerador.Atributos[i].Caption);
end;

procedure TfrmPensarEnClases.btnBajarClick(Sender: TObject);
var
  fAtrib: TAtributo;
  i: Integer;
begin
   i:= lbxAtributos.ItemIndex;
   fAtrib:= FGenerador.Atributos[i];
   if i >= 0 then begin
      with FGenerador do  SetDownPosition(fAtrib);
      ActualizarInterfaz;
      lbxAtributos.Itemindex:= fAtrib.GetPosicion;
   end;
end;

procedure TfrmPensarEnClases.btnSubirClick(Sender: TObject);
var
  fAtrib: TAtributo;
  i: Integer;
begin
   i:= lbxAtributos.ItemIndex;
   fAtrib:= FGenerador.Atributos[i];
   if i >= 0 then begin
      with FGenerador do  SetUpPosition(fAtrib);
      ActualizarInterfaz;
      lbxAtributos.Itemindex:= fAtrib.GetPosicion;
   end;
end;

procedure TfrmPensarEnClases.FormCreate(Sender: TObject);
begin
   FGenerador:= TGenerador.Create;
   with FGenerador do begin
      AddAtributo.Caption:= 'Caracteristica';
      AddAtributo.Caption:= 'Color';
      AddAtributo.Caption:= 'Tipo';
   end;
   ActualizarInterfaz;
   lbxAtributos.ItemIndex:= 0;
end;

procedure TfrmPensarEnClases.FormDestroy(Sender: TObject);
begin
   if Assigned(FGenerador) then FreeAndNil(FGenerador);
end;

end.

Algunas ideas nos pueden ayudar en esos primeros razonamientos:

* En este caso concreto, tanto la clase TGenerador como TAtributo, han descendido de TObject, que es el ascendente comun a todas las clases. Podríamos haber razonado que, por ejemplo, TAtributo, descendiera de un control visual, pudiendo ser insertado en nuestro formulario, lo cual no es ni mas ni menos correcto, ya que forma parte del abanico de decisiones de diseño que nuestra experiencia  puede valorar. Hacerlo de una forma o de otra, va a condicionar necesariamente las relaciones a las que voy a quedar ligado. Quizás por esa razón y por evitar ligarnos a ninguna representación es por lo que he optado por partir de TObject. Como hemos hecho que descienda de ésta, necesitábamos un procedimiento que sea capaz de recrear la instancia del Generador por lo cual, se ha implementado  ActualizarInterfaz. Tambien se ha hecho necesario destruir explicitamente la instacia del Generador y liberar la reserva de memoria que ha necesitado su creación. Lo hemos hecho en el evento OnDestroy de nuestro formulario.

* La clase TGenerador, necesita almacenar una lista de referencias a las distintas instacias de TAtributo, y para ello, una buena opción es hacer uso de la clase TList, que es especificada e implementada dentro del módulo Classes.pas. TList es una lista de punteros y un aliado extremadamente poderoso, ya que puede almacenar cualquier cosa. En contrapartida, la manipulación de cualquiera de las referencias a las que apuntamos desde nuestra lista de punteros, necesitaría inevitablemente de una conversión de tipos para acceder al objeto instanciado. 

Este módulo es bastante interesante pues contiene las definiciones de algunas clases muy básicas que en buena medida se correlacionan con algunos TDA´s clásicos de la programación, como la gestión de listas, pilas y colas. Estos dos ultimos (pilas y colas) se apoyan en la clase TList y se especifican e implementan en el modulo Constnrs.pas. En Classes.pas, además se incluyen los hilos de ejecución (TThreads), las interfaces, los enumeradores, la clase TStream y otras más, imprescindibles y recurrentes dentro del esquema de la VCL.

La miembros y metodos de TList, nos permiten de forma sencilla, generar por ejemplo el acceso a un atributo determinado, a través de una propiedad de tipo array que se gestiona con el índice de la lista. Tambien nos permite intercambiar de posición dos referencias. No tenemos que ir reinventando la rueda en aquellos puntos en los que nos podamos valer de clases que ya nos dan una funcionalidad. ¿no os parece?.

* Otra idea interesante, podría ser que el atributo conozca a la clase que va a gestionarlo, lo cual nos permitirá, invocar metodos que se ejecutan desde ésta, de ser necesario. Por ello, la creación del mismo atributo, parte del generador, que entrega una referencia a si mismo en el constructor de la clase TAtributo:   

constructor Create(AGenerador: TGenerador); virtual;

La invocacion de AddAtributo instancia un nuevo atributo y lo añade a la lista, devolviendo como valor de retorno una referencia al objeto creado.

function TGenerador.AddAtributo: TAtributo;
begin
   Result:= TAtributo.Create(Self);
   FAtributos.Add(Result);
end;

El constructor guarda esta referencia:
 constructor TAtributo.Create(AGenerador: TGenerador);
begin
  if not Assigned(AGenerador)  then
     Raise Exception.Create(‘Error: Referencia al generador no valida’);
   FGenerador:= AGenerador;
end;

Podemos ver un ejemplo en el código que hemos escrito. El método GetPosición de la clase TAtributo, nos devuelve la posición del mismo dentro de la lista. Esto podría obtenerse de varias formas. Guardando en un miembro privado el valor de esta posición cuando es añadido el atributo, siendo actualizado cada vez que es modificada la posición del mismo en la lista. Esa podría haber sido una opción. Sin embargo, finalmente, al guardar la referencia al generador, obtener ese indice es tan fácil como preguntarle a quien realmente lo sabe:  :-)

function TAtributo.GetPosicion: Integer;
begin
  Result:= FGenerador.GetPosicion(Self);
end;
  

Lo dejamos aquí y nuestro siguiente paso será ir añadiendo detalles a este escenario.

Nuevo Twibe delphiespanol: ¿Te unes?

mayo 17, 2009 en ¿Sabías que...?, Consejo, Delphi, Enlace interesante, Entrada Diario, Noticias, Noticias Delphi

Dichosa ñ, como se le tira de menos.  :-)

Hoy podemos compartir una noticia bastante positiva. Si existía una tribu para los programadores de delphi de habla inglesa, ¿por qué no también para los programadores hispanos? Así que cuando he visto el mensaje de Andreano Lanusse donde comentaba que ya se habia abierto esta comunidad en twibes, he pensado que no habia tiempo que perder para apuntarse, y de la misma forma que me habia suscrito en http://www.twibes.com/group/delphi, tambien lo he hecho en http://www.twibes.com/group/delphiespanol, con mas razón todavía.

Twibes Hispano

De hecho, comparto con vosotros que estoy dando mis primeros pasos para mejorar mi inglés, que al día de hoy me permite leer la documentación que necesito, pero desgraciadamente no me permite poder seguir los videos o escribir con corrección y participar de recursos que pueda llevar a mi comunidad. Esa es un poco la idea y en ello estoy. Tiempo al tiempo.  

Por otro lado, tengo la esperanza de que todas estas iniciativas que están llevando a cabo potenciarán nuestra comunidad y nuestra herramientas de desarrollo. Nos dan una oportunidad para salir de los silencios y llevar nuestra voz y nuestras inquietudes mas lejos. ¿De verdad vais a dejarlas pasar?

Nos vamos de visita a…

mayo 17, 2009 en Delphi, Enlace interesante, Entrada Diario

Auque ya está añadido a la sección de enlaces, os aconsejaría revisar el blog de German Estevez (Neftalí)

http://neftali.clubdelphi.com/

Contiene algunas entradas nuevas, como por ejemplo la que hace referencia a GoogleMaps, escrita hace unos días por Germán.

http://neftali.clubdelphi.com/?p=380

img_googlemaps

Nueva apariencia, nuevo contenido y algunos articulos antiguos que me parecen muy, muy interesantes y que ¡ojala!, encontraran continuación.

Por ejemplo el que habla de pluggins.

http://neftali.clubdelphi.com/?p=196

Estoy seguro de que muchos compañeros desearian leer esa segunda parte y desde aquí animo a Germán a que lo continue.

Así que lo dicho… la visita se hace imprescindible.

Experimentos, reflexiones y otros artefactos (II)

mayo 17, 2009 en Advertencia, Artículos, ¿Sabías que...?, ¿Sabías que...? [Delphi], Código, Delphi, Entrada Diario, Taller práctico

Seguimos avanzando en el artículo de la primera parte de la serie.

¿Por donde ibamos? Sí. Ya…

Nuestro formulario iba creciendo. De hecho habíamos incluído una pequeña modificación que invertía el código y el formulario, comenzaba a parecerse -con la prudencia que hace falta para comentar ésto ya que estas lineas son meramente experimentales- a una hipotética herramienta para generar combinaciones de códigos. Esto nos permite tomar una pequeña dosis de realidad en nuestro razonamiento. Una herramienta que iba a crecer pero ligada desgraciadamente a los componentes que iban formando su interfaz.

No. No creais que es algo irreal o fantástico. Aunque no es demasiado habitual, algunas empresas tratan sus artículos como una concreción de las características que contienen los patrones modelos y escogen los escenarios en los que se hace efectivo este paso de materialización. Por ejemplo al ser cursado un pedido por parte del cliente, momento en el que podrían las distintas selecciones de caracteristicas desembocar en la generación de un código único y desencadenar los proceso de alta en artículos e inserción en lineas de detalle de pedido. Y no confundais por favor este código necesariamente con la clave primaria de una tabla cualquiera, entre otras cosas porque no hay nada que impida que puedan coexistir una clave primaria incremental (o no incremental), con cualquier otra combinaciones de claves que acaban formado parte de un índice de clave única.

En este ejemplo, vamos descubriendo algunos detalles sobre la marcha. ¿Eso pasa tambien en los proyectos reales, no es así?. Nos añadiran un mes despues una caracteristica que tambien vamos a codificar con dos caracteres. Con la salvedad de que al parecer no es combinable, como sí ocurría con los dos atributos que ya conocíamos: el color y el tipo. Sera constante y variable para una combinación determinada de color/tipo, bien por selección de una entre una lista asociada a esta, bien por afinidad a uno de los atributos, por lo que hemos convenido en denominar ese comportamiento como ”rellenable de”. Esto que parece muy complejo lo vereis muy sencillo en el código. 

Pero lo mejor es que lo veais en una imagen del formulario, una vez que hemos hecho las modificaciones. Nuestro bucle “for” va creciendo y va anidadandose para generar las combinaciones. Para hacerlo un poco mas real el ejemplo, he añadido varios componentes TClientDataSet, asociados a cada uno de los atributos, y he almacenado localmente los datos en tres ficheros xml que cargo al principio y guardo al final del proceso. Esto es meramente anecdótico y para evitar conexiones reales que ya se pueden sobreentender. 

 

Formulario

Descargar
 

unit URelaciones;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, DB, DBClient, TConnect, Provider;

type
  TRelaciones = class(TForm)
    lbxTipo: TListBox;
    lbxColor: TListBox;
    lbxResultados: TListBox;
    rgpCodigo: TRadioGroup;
    bnSolucion: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    cdsTipo: TClientDataSet;
    cdsTipoTipo: TStringField;
    cdsColor: TClientDataSet;
    StringField2: TStringField;
    cdsTipoIDTipo: TIntegerField;
    cdsColorIDColor: TIntegerField;
    cbxCaracteristica: TComboBox;
    cdsCaracteristica: TClientDataSet;
    cdsCaracteristicaIdCaracteristica: TIntegerField;
    cdsCaracteristicaCaracteristica: TStringField;
    chbRellenar: TCheckBox;
    Bevel1: TBevel;
    procedure FormCreate(Sender: TObject);
    procedure bnSolucionClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure chbRellenarClick(Sender: TObject);
  private
    { Private declarations }
    procedure SimulaDatosEnBBDD;
    procedure SimulaPermanenciaDatos;
  public
    { Public declarations }
  end;

var
  Relaciones: TRelaciones;

implementation

{$R *.dfm}

procedure TRelaciones.bnSolucionClick(Sender: TObject);
var
 i,j, k: Integer;
 s: String;
begin
   lbxResultados.Clear;
   for i := 0 to lbxTipo.Count - 1 do
      for j := 0 to lbxColor.Count - 1 do begin
          case rgpCodigo.ItemIndex of
           0: s:= lbxTipo.Items[i]+ lbxColor.Items[j];
           1: s:= lbxColor.Items[j]+ lbxTipo.Items[i];
          end;
      case chbRellenar.Checked of
        True: lbxResultados.items.Add(lbxColor.Items[j]+s);
        False: lbxResultados.items.Add(cbxCaracteristica.Items[cbxCaracteristica.ItemIndex]+s);
      end;
   end;
end;

procedure TRelaciones.chbRellenarClick(Sender: TObject);
begin
   cbxCaracteristica.Enabled:= not chbRellenar.Checked;
end;

procedure TRelaciones.FormCreate(Sender: TObject);
begin
  SimulaDatosEnBBDD;

  if not cdsColor.Active then cdsColor.Open;
  cdsColor.First;
  while not cdsColor.Eof do begin
    lbxColor.Items.Add(cdsColor.FieldByName('Color').AsString);
    cdsColor.Next;
  end;

  if not cdsTipo.Active then cdsTipo.Open;
  cdsTipo.First;
  while not cdsTipo.Eof do begin
    lbxTipo.Items.Add(cdsTipo.FieldByName('Tipo').AsString);
    cdsTipo.Next;
  end;

  if not cdsCaracteristica.Active then cdsCaracteristica.Open;
  cdsCaracteristica.First;
  while not cdsCaracteristica.Eof do begin
    cbxCaracteristica.Items.Add(cdsCaracteristica.FieldByName('Caracteristica').AsString);
    cdsCaracteristica.Next;
  end;
  cbxCaracteristica.ItemIndex:= 0;
end;

procedure TRelaciones.FormDestroy(Sender: TObject);
begin
  //guardamos los datos antes de finalizar
  SimulaPermanenciaDatos;
end;

procedure TRelaciones.SimulaDatosEnBBDD;
begin
  cdsColor.FileName:= 'Color.xml';
  cdsColor.CreateDataSet;
  cdsColor.Active:= True;
  cdsColor.Insert;
  cdsColor.FieldByName('IDColor').AsInteger:= 1;
  cdsColor.FieldByName('Color').AsString:= '10';
  cdsColor.Insert;
  cdsColor.FieldByName('IDColor').AsInteger:= 2;
  cdsColor.FieldByName('Color').AsString:= '12';
  cdsColor.Insert;
  cdsColor.FieldByName('IDColor').AsInteger:= 3;
  cdsColor.FieldByName('Color').AsString:= '15';
  cdsColor.Post;

  cdsTipo.FileName:= 'Tipo.xml';
  cdsTipo.CreateDataSet;
  cdsTipo.Active:= True;
  cdsTipo.Insert;
  cdsTipo.FieldByName('IDTipo').AsInteger:= 1;
  cdsTipo.FieldByName('Tipo').AsString:= 'AA';
  cdsTipo.Insert;
  cdsTipo.FieldByName('IDTipo').AsInteger:= 2;
  cdsTipo.FieldByName('Tipo').AsString:= 'AB';
  cdsTipo.Insert;
  cdsTipo.FieldByName('IDTipo').AsInteger:= 3;
  cdsTipo.FieldByName('Tipo').AsString:= 'CC';
  cdsTipo.Post;

  cdsCaracteristica.FileName:= 'Caracteristica.xml';
  cdsCaracteristica.CreateDataSet;
  cdsCaracteristica.Active:= True;
  cdsCaracteristica.Insert;
  cdsCaracteristica.FieldByName('IDCaracteristica').AsInteger:= 1;
  cdsCaracteristica.FieldByName('Caracteristica').AsString:= '0A';
  cdsCaracteristica.Insert;
  cdsCaracteristica.FieldByName('IDCaracteristica').AsInteger:= 2;
  cdsCaracteristica.FieldByName('Caracteristica').AsString:= '0B';
  cdsCaracteristica.Insert;
  cdsCaracteristica.FieldByName('IDCaracteristica').AsInteger:= 3;
  cdsCaracteristica.FieldByName('Caracteristica').AsString:= '0C';
  cdsCaracteristica.Post;

end;

procedure TRelaciones.SimulaPermanenciaDatos;
begin
   cdsColor.SaveToFile('color.xml');
   cdsTipo.SaveToFile('tipo.xml');
   cdsCaracteristica.SaveToFile('Caracteristica.xml');
end;

end.

Todavía no hemos hecho un solo razonamiento que nos pueda indicar que nuestro chip “pensar en clases” está activado. :-)

Eso sí, hemos sido capaces de añadir una característica más y enrevesar nuestro código otro tanto. Y dado que ahora mismo tan solo contamos con un modelo que contiene tres atributos, me hace sospechar que al tener una cantidad mayor, aumentaria la complejidad de las relaciones, (representadas en esos bucles y las distintas estructuras que permtien bifurcar el fllujo de nuestro codigo), de forma peligrosa. Esa es quizás la moraleja de esta segunda parte y la que nos debería hacer pensar que estamos atando una soga a nuestro cuello y que no va a depender de nosotros que acabe ahogandonos.

Comparar las tres versiones del bucle:

   for i := 0 to lbxTipo.Count - 1 do
      for j := 0 to lbxColor.Count - 1 do
          lbxResultados.Items.Add(lbxTipo.Items[i]+ lbxColor.Items[j]);
   for i := 0 to lbxTipo.Count - 1 do
      for j := 0 to lbxColor.Count - 1 do
          case rgpCodigo.ItemIndex of
           0: lbxResultados.Items.Add(lbxTipo.Items[i]+ lbxColor.Items[j]);
           1: lbxResultados.Items.Add(lbxColor.Items[j]+ lbxTipo.Items[i]);
          end;
   for i := 0 to lbxTipo.Count - 1 do
      for j := 0 to lbxColor.Count - 1 do begin
          case rgpCodigo.ItemIndex of
           0: s:= lbxTipo.Items[i]+ lbxColor.Items[j];
           1: s:= lbxColor.Items[j]+ lbxTipo.Items[i];
          end;
      case chbRellenar.Checked of
        True: lbxResultados.items.Add(lbxColor.Items[j]+s);
        False: lbxResultados.items.Add(cbxCaracteristica.Items[cbxCaracteristica.ItemIndex]+s);
      end;
   end;

 

Podria darse el caso de que existieran relaciones de dependencia entre uno o varios atributos sin ir mas lejos. Ahora mismo no las estamos considerando. Por relaciones de dependencia entiendo por ejemplo, la existencia de restricciones que permitan combinar dos valores concretos de distintos atributos. Imaginad que para un determinado tipo no pudiera combinarse determinados colores (a efectos reales puede asimilarse a una relación maestro detalle entre los valores de dos atributos distintos, pero con la peculiaridad de que esos detalles son compartidos) .

Un ejemplo:

La bicicleta A contiene el chasis ’00′ y este puede venderse en los colores ’00′ (negro), ’01′ (rojo), ’02′ (azul)

La bicicleta B contiene el chasis ’01′ y este puede venderse en los colores  ’00′ (negro), ’03′ (beig), ’06′ (plata)

Como veis, ahora queda mas claro. Comparten el color ’00′ pero cada tipo solo se combina con determinados colores.

  ¿Que hariamos entonces? Tendriamos que actuar posiblemente en el interior de cualquiera de las estructura case antes de que se ejecutase los metodos añadir una linea a nuestros resultados de forma que se pudieran restringir las combinaciones y se pudiera desechar las que no son validas.

Es mas, la primera pregunta que podríais preguntaros es por qué tengo que suponer que sean tres, cuatro o x numero finito de elementos. Estoy simplemente generando una fotografia de los requerimientos actuales sin valorar que estos puedan cambiar y que puedan crecer el numero de ellos, por asumir que sea uno de los cambios que mas facilmente puedan producirse. Ese es uno de los errores en los que podemos facilmente caer en ocasiones. De haber contemplado esta posiblidad posiblemente hubiera sido facil generar un nuevo interfaz que asuma la nueva situación. Pensar en termino de clases no es la panacea de todos los males ni evita la complejidad intrinseca del elemento estudiado, pero si que nos permite minimizar los efectos de los cambios en los requerimientos. Un razonamiento correcto quizás nos hubiera descubierto una clase “Atributo”, capaz de manipular los distintos valores que puede manejar en funcion de un dominio. Podría establecer relaciones igualmente entre otros atributos y el mismo. Por poner algunos ejemplos que se me vienen así a “botepronto”. Asimismo, podríamos especificar una clase que permitiera gestionar añadir nuevos atributos, eliminarlos, que el orden de presentación fuera variable, etc.

Creo que todo esto encaja en la idea que mueve esta segunda parte ‘pensar en terminos de clases’… :-)

Lo dejamos aquí… y seguimos en la tercera parte. Espero y deseo que todos estos razonamientos os puedan ser de alguna utilidad.

Tribus y comunidades…

mayo 16, 2009 en ¿Sabías que...?, ¿Sabías que...? [Delphi], Delphi, Enlace interesante, Entrada Diario, Noticias, Noticias Delphi

Esta noche cambiamos de tercio, ya que me parecía mas adecuado dejar la segunda parte del artículo anterior para el fin de semana, que tengo algo más de tiempo y lo disfruto más. :-)  Y como prácticamente ya es media noche, al menos sí que me da tiempo a compartir con vosotros unas lineas aunque sean breves.

Hace un par de días quería haber comentado esta curiosidad. No se si habéis pasado ultimamente por la web de embarcadero, en la zona que se ubican los blogs de la comunidad de programadores. No es que vaya mucho por esa zona pero sí es cierto que de cuando en cuando me paso por ver si hay algun enlace interesante o alguna noticia que podemos insertar.

Podéis leer en el blog de David Intersimone:

http://blogs.embarcadero.com/davidi/2009/05/07/39623

que recientemente han abierto una comunidad Twibe, que han llamado Delphi y Delphi Prism con el fin de que se sumen un buen numero de programadores y sigan el día a día de las novedades de estos entornos.

Podéis curiosear, y si os apetece inscribiros en ella.

http://www.twibes.com/group/delphi

Comunidad Delphi Twibes

Para formar parte, tenéis que abrir una cuenta en www.twitter.com y con ella, iniciar sesión en la pagina de la comunidad Twibe.

La pregunta que puede quedar en el aire es para “qué”… La tenéis escrita en la frente. :-) La lista es una especie de tablón de mensajes rápidos, donde normalmente insertan vínculos a paginas en las que escriben, a través de  comentarios muy breves. Os animo a que al menos le deis un vistazo.