|
Como ya comentábamos en el ejercicio anterior, nuestra pretensión ahora, es modificar la aplicación, de tal forma que siga manteniendo las funcionalidades dentro del nuevo marco. Pero veamos esquemáticamente en que nos ha variado: Marco Antiguo: Marco Nuevo: En el nuevo marco de estudio consideramos una relación nueva que puede
ser establecida y que nos dice que un producto terminado puede llegar a
convertirse en materia prima de otro producto terminado distinto. PRODUCTO GAMMA = (PRODUCTO BETA)' + MATERIA H Imaginemos que nuestro usuario anda algo despistadillo, ¡horror! ¡va a
modificar la primera igualdad! Puesto que (PRODUCTO GAMMA)' existe como materia prima no hay ninguna razón que nos diga que no pueda ser asignada a PRODUCTO ALFA. Hemos creado, de esta forma y sin darnos cuenta, las referencias
circulares que nos hechas al traste nuestra pequeña aplicación, porque:
¿Qué os parece...? Cuando finalicé la redacción del tercer ejercicio me preguntaba como podría garantizar que se pudieran cumplir las propiedades de la herencia: ningún derivado puede formar parte de la definición del objeto que le dio origen. Lógicamente nuestro producto debía de conocer de alguna forma las materias primas iban a entrar en su composición. Cualquier asignación de nuevas materias primas o modificación de las existentes debía de ser reconocida por el y aceptada o no según procediera. Lo primero que se me ocurrió fue que se podría dar un identificador único a cada materia prima en el momento de su creación y que nuestro producto dispusiera en un campo, una cadena de caracteres que resultara de la unión de todos los identificadores asignados. Así pues, considerando: MATERIA A = 345456 MATERIA B = 444343 (PRODUCTOALFA)' = 345456444343 PRODUCTO ALFA dispondría de un campo en la tabla de Productos Terminados cuyo nombre podría ser, por ejemplo DERIVADOS y que recogería el valor de la materia prima que se ha generado con él. En el momento de realizar una nueva asignación, tal que PRODUCTO ALFA = (PRODUCTO GAMMA)' + MATERIA B podríamos buscar en esa cadena, si en el identificador de (PRODUCTO GAMMA)' se encuentra incluido el identificador de PRODUCTO ALFA. Si esto fuera así podríamos cancelar el proceso y garantizar de esa manera la integridad de las relaciones. ah... no todo es perfecto. Aparentemente todo funciona bien. Si os
fijáis esto es tan solo aparentemente ya que a medida que nuestra base de
datos crezca, y crezca el numero de estructuras anidadas, crecerá
proporcionalmente la dificultad de garantizar la integridad de las
relaciones. Tenía que haber otra forma... ¡claro! la misma VCL nos daba un idea
mejor. Ella misma mantenía el sistema de Propietarios (Owner) con distintas
funcionalidades, liberar memoria al destruir cada objeto, etc... Cada
componente sabía quien era su Propietario... Manos a la obra. Vamos a crear el algoritmo que nos devuelva verdadero o
falso en el caso de que la materia prima a asignar tenga relaciones con el
producto sobre el que va a recaer la asignación. Vamos a intentar explicar el mecanismo de operación del algoritmo: *Partimos de un contenedor
vació. |
| function
TfrmRelaciones.BuscaDerivado( Producto_asignado: String; Materia_arrastrada:
String): Boolean; var actualizador: TQuery; comprobador: TQuery; contenedor: TStringList; derivados: String; materia_derivada: String; begin // creamos los dos querys que necesitamos actualizador:= TQuery.Create(self); comprobador:= TQuery.Create(self); // creamos un contendor de strings contenedor:= TStringList.Create; // asignamos un valor inicial a la función para que no pueda quedar indeterminada result:= false; try
//si no existe un producto en la tabla de
productos que tenga como derivado la materia prima arrastrada
finally
|
|
Si habéis llegado a entender con claridad el desarrollo del algoritmo quizá pensareis que siguiendo un procedimiento parecido a éste, se podría montar un árbol binario a partir de considerar las relaciones propietario/poseedor. Este algoritmo podría ser utilizado para recomponer una situación inicial en una aplicación orientada a objetos en donde cada objeto puede necesitar interrelacionarse con otros. Vamos a modificar la ficha de productos terminado ampliando los nuevos campos de los que vamos a disponer, así como el nuevo botón de actualizar precios, que nos producirá las actualizaciones en cascada. Disponemos además de un nuevo campo llamado incremento que vendrá a sumar al precio de coste del producto un margen de beneficio previo a la consideración de materia prima. Su precio como materia prima será el equivalente a un precio de venta mínimo de producto. Tal y como queda la nueva ficha: |
![]() |
|
Nos queda todavía pendiente una cosa. Necesitamos mantener la
funcionalidad de nuestra aplicación y garantizar que los productos, a
cualquier nivel estructural, serán actualizados ante la modificación del
precio de las materias primas. Como podemos ver es muy importante el que se abra la tabla antes de hacer las comprobaciones ya que nos permite que en la siguiente pasada del bucle, siempre encuentre actualizado el valor del producto por las modificaciones efectuadas en el precio de las materias primas. Aunque nosotros hayamos trasladado la operativa del algoritmo a un solo nivel, virtualmente, en cada una de las pasadas del bucle es semejante a movernos a un nivel estructural superior. El proceso lo podemos adornar, tal y como se hace en este procedimiento de un panel que integra dos barras de progreso. La primera mantiene el progreso en el bucle que recorre todos los registros de la tabla de productos. La segunda, fuera del bucle, mantiene el nivel estructural actual. Es decir, que un ciclo completo en la barra primera aumenta en un paso la barra de progreso numero dos. |
| procedure
TfrmProductosTerminados.bib_ActualizarClick(Sender: TObject);
var repetirproceso: boolean; xIndice: Integer; apuntado: TBookmark; panelcontenedor: TPanel; barraprogreso1, barraprogreso2: TProgressBar; etiqueta1, etiqueta2: TLabel; actualizador: TQuery; begin if bib_Actualizar.down then begin EstadoControles(False); //en
el caso de que no esté en estado de visualización abortamos el
proceso try
with barraprogreso1 do with etiqueta1 do with
barraprogreso2 do with etiqueta2 do repetirproceso:=
true;
Inc(xIndice);
modulo1.tabla_productos_maestra.Next; if xIndice = 0
then repetirproceso:= false;
finally |
|
Me queda tan solo comentar una cosa: para poder garantizar un funcionamiento óptimo, tenemos que restringir ciertas acciones al usuario tales como: *El usuario no puede modificar el precio de una materia prima que sea
derivada de un producto terminado. Esto es clave. De hecho el proceso de
derivación de un producto terminado lo proporcionaremos de forma automática
para que no se produzca dicha intervención. El usuario dispondrá de una
ventana en la que aparecen todos aquellos productos que todavía no se han
convertido en materia prima y sobre estos realizará una elección. Otras consideraciones son de obligado cumplimiento: Todas estas consideraciones nos permitirán garantizar la integridad del proceso. |