Procesando dinámicamente fórmulas creadas por el usuario
 

Fecha: 28/Feb/2005 (15/02/2005)
Autor: Luis Armando Canchala F. ( canchala@hotmail.com)

 


En algunas ocasiones, los requerimientos de una aplicación piden el procesamiento dinámico de formulas, las cuales son creadas y manejadas directamente por el usuario.

 

Esta situación puede presentarse fácilmente en un aplicativo de calidad de una fabrica de cualquier ramo, pues los análisis de calidad de los productos en proceso y/o terminados, de materia prima, material de empaque, de proveedores, etc,  requieren de innumerables variables y fórmulas entre esas variables. Las variables y fórmulas de esos productos pueden estar aumentando o cambiando constantemente

 

Cuando una aplicación está conformada por gran cantidad de fórmulas, el analista programador tiene dos opciones: resolver las fórmulas desde el código, luego de definir con el usuario cuáles son las fórmulas y còmo se resuelven, o desarrollar un mecanismo a través del cual, los usuarios guarden las fórmulas en una base de datos y desde allì un objeto las lea, las procese y las resuelva devolviendo el resultado.

 

La primer opción no es práctica, puesto que el código queda atado al programador, ya que cuando cambien una fórmula, o se cree una nueva fórmula, éste debe entrar al código e implementar la solución a aquella. Esta situación es lenta además, y puede generar errores, además que cuando el programador ya no esté, como se resuelve una situación nueva?.

 

La segunda opción es la ideal, ya que consiste en que el usuario cree y mantenga sus fórmulas en una base de datos tal como él las necesite según su trabajo. Si llega una nueva variable a medir para una fórmula ya existente, o nuevas fórmulas para alguno  de sus procesos, simplemente usa el software para registrar dichas fórmulas, siguiendo algunos controles, y ya queda disponible para que el programa las procese dinámicamente cuando el usuario lo requiera, sin necesidad de llamar al programador.

 

A continuación se presenta un pequeño programa como muestra, donde se crea el mecanismo para solucionar esta situación a favor del usuario. Se utiliza un objeto DataTable, el cual se crea de acuerdo a los componentes de cada fórmula, donde cada variable de dicha fórmula corresponde a una campo de la DataTable. Esto significa que cada que se procese una fórmula se creará un nuevo DataTable diferente a los anteriores, pues cada fórmula tiene sus propios componentes. Al objeto DataTable se le adiciona al final una columna, la cual representa la expresión que resuelve la fórmula usando los campos previos del DataTable de la misma fórmula.

 

Para simplificar el procedimiento, se utilizan tres DataGrids, donde se guardan varias fórmulas, valores de sus componentes, y se simula el proceso mostrando el resultado al final. En la realidad se deberá implementar un software acorde con las necesidades del caso.

 

El primero muestra una serie de fórmulas que originalmente se encuentran en una tabla de una base de datos. Lo especial de estas fórmulas, es que el usuario es quien las crea y modifica, y las almacena en la DB.

 

En el segundo DataGrid se muestran varios valores que también están originalmente en una tabla de la base de datos. Estos valores corresponden a variables que componen las fórmulas. Estos valores se almacenan en la base de datos como resultado de procesamientos varios de otras fórmulas o de datos capturados desde el teclado o de otro sistema conectado al nuestro.

 

El tercer DataGrid muestra el resultado al procesar una formula; además podemos ver el valor de cada uno de sus componentes, los cuales vemos en el DataGrid2

 

Para probar con un ejemplo este proceso, tomamos la primera formula del DataGrid1:

                 

               UTILIDAD =  (   (  INGRESOS  –  EGRESOS  )  *  FACTOR  )

 

 

 

PROCEDIMIENTO

 

Vemos que la formula tiene 3 componentes o variables: INGRESOS, EGRESOS y FACTOR.

Para su solución, según lo vimos arriba, se creará el DataTalbe con tres campos llamados así como esos componentes:

   Campo 1 =  INGRESOS

   Campo 2 =  EGRESOS

   Campo 3 =  FACTOR

 

Así mismo, se crea un cuarto campo a la tabla, que se puede llamar asi:

   Campo 4 = RESULTADO,

 

Los campos 1 al 3, deberán almacenar los valores para cada uno de ellos, los cuales provienen de algún proceso, de otra tabla o de otro sistema.

El campo 4, será un campo tipo expresión que contendrá la formula :

    ((INGRESOS – EGRESOS ) * FACTOR

 

Al momento de llenar los datos de los campos 1 al 3, ya tendremos el resultado de la fórmula en el campo 4. Este resultado se envía al objeto llamador.

 

  

 

Con respecto al ejemplo en csharp tenemos, que para el procesamiento de resolver la fórmula elegida , se utiliza la clase procesaformulas , la cual se encarga de obtener el resultado.

 

Desde el programa llamador, debo instanciar ese objeto:

 

                          ProcesaFormulas MiProceso = new ProcesaFormulas();

 

A este objeto le asigno el valor de la formula a procesar, el cual es, para  nuestro ejemplo UTILIDAD; invoco el método Procesar() de este objeto, y en seguida ya tendré el Resultado en txtResultado.

 

 

                        MiProceso.Variable=txtVariable.Text;   // Es decir UTILIDAD

                        MiProceso.Procesar();   

                        txtResultado.Text=MiProceso.Resultado.ToString(); // Es 240000

 

El método Procesar() es el encargado de realizar el proceso de resolver la fórmula que recibe. Para esto lo primero que hace es la expresión. En segundo lugar desglosaría esa fórmula en sus componentes.  En seguida obtener el valor de cada componente. Por ultimo, para calcular el resultado, operando esos datos de esos componentes.

 

                            LeerFormula();

                          DesglozarFormula();

                          LeerValorOperandos();

                          CalculaResultado();

 

 

Para efectos de simplificar el ejemplo se utilizan funciones que asumen lecturas a alguna base de datos (aquí no usamos ninguna base de datos, es solo una referencia), pero en la practica este procedimiento se puede adaptar a cualquier clase de situaciones con formulas muchísimo más complejas con el uso de cualquier operador y funciones válidas por el compilador. De hecho existe un aplicativo para control de análisis de un Laboratorio Industrial (en 4gl).

 

A continuación veamos el código de la clase que resuelve la formula. De todas formas incluyo adjunto el programa completo.

 

Te recuerdo clickar en la calificación de PanramaBox para seguir avanzando en el proyecto de Cinco Estrellas.

 

 

 

--CLASE PARA EL PROCESAMIENTO

using System;
using System.Collections;
using System.Data;

namespace tablas_ADO
{
   /// <summary> 
   /// Summary description for ProcesaFormulas.
   /// </summary> 
   public class procesaformulas 
   {
     public ProcesaFormulas()
     {
       //
       // TODO: Add constructor logic here
       // 
     }
                       // El codigo de la variable a resolver con la formula asociada
     protected string variable; 
     // Formula definida por el usuario, la cual se resuleve dinámicamente
     protected string formuladescriptiva; 
     // Resultado de la operacion
     protected double resultado; 
     // Lista de Operando o variables que conforman la formula. Estos se
     // obtienen al desglozar la formula en sus componentes, sin operadores
     protected string [] listaOperandos = new string[5]; 
     // Lista del valor de cada operando o variable de la formula. Estos
     // valores son los que entran a operar en la formula asociada.
                       protected double [] listaValores = new double[5]; 
     // Tabla para desplegar el resultado
     public DataTable Tbl = new datatable(); 


     // Estas propiedades permites pasar los datos desde esta clase a la
     // clase llamadora
     public string variable 
     {
       set 
       {
         this .variable=value; 
       }                                      
     }

     public string formuladescriptiva 
     {
       get 
       {
         return this .formulaDescriptiva;
       }
     }

     public double resultado 
     {
       get 
       {
         return this.resultado; 
       }                                      
     }

     public void procesar() 
                       {
                                  LeerFormula();
       DesglozarFormula();
       LeerValorOperandos();
       CalculaResultado();

     }

     private void leerformula() 
     {
       // Se debe obtener de la Base de Datos la formula que se desea procesar.
       // Este dato lo graba y modifica el usuario en algún momento, con su 
       // correspondiente control. Aqui, por efecto de simplificar el ejemplo, se
       // asume que ya se obtuvo la formula correcta una lectura a la DB.
                   this .formulaDescriptiva = "( INGRESOS - EGRESOS ) * FACTOR ";
     }

     private void desglozarformula() 
                        {   
       // Se debe llenar este array ListaOperandos[], con los operandos
       // componentes de la formula obtenida arriba. 
       // Este proceso debe asegurar 
       // estos compoentes son solo operandos o constantes numéricas, pero
       // no operadores. Aqui, para efecto del ejemplo se asume que la formula
       // fue desglozada asì:
       listaOperandos[0]="INGRESOS";
       listaOperandos[1]="EGRESOS";
       listaOperandos[2]="FACTOR";
       listaOperandos[3]=" ";
       listaOperandos[4]=" ";

     }
     private void leervaloroperandos() 
     { 
       // Para cada operando de la lista anterior, ListaOperandos[], se obtiene
       // un valor que está grabado en la Base de Datos, y que son resultados
       // de digitaciones o de otros cálculos. Esta nueva lista de valores, se
       // debe llenar con datos que se relacionan con la lista de arriba.
       // Por simplicidad se asume que se llena asì:
       listaValores[0]=1000000;
       listaValores[1]=800000;
       listaValores[2]=1.2;
       listaValores[3]=0;
       listaValores[4]=0;

     }

     private void calcularesultado() 
     { 
       // Se crea una tabla en memoria con los datos de la listaOperandos, o sea
       // los campos o componentes de la formula. Al final se inluye siempre el
       // campo RESULTADOS de tipo expresion, el cual contiene la formula leida
       // arriba para la variable en proceso: en este caso UTILIDAD. 
                   // Al instante de crear esta tabla, se tendrá resuelta la fórmula en este
       // campo RESULTADO.                    
       Tbl.Columns.Add("VARIABLE", typeof (string)); 
       Tbl.Columns.Add(listaOperandos[0], typeof (double)); 
       Tbl.Columns.Add(listaOperandos[1], typeof (double)); 
       Tbl.Columns.Add(listaOperandos[2], typeof (double)); 
       Tbl.Columns.Add("RESULTADO",
        typeof(double ),this.formuladescriptiva); 
       {
         // Crea una nueva línea
         DataRow Linea = Tbl.NewRow();
         // Coloca los datos en cada una de las columnas de esta línea
         Linea[0] = this.variable; 
         Linea[1] = listaValores[0];
         Linea[2] = listaValores[1];
         Linea[3] = listaValores[2];

         // Agrega la línea en la tabla
         Tbl.Rows.Add(Linea);
         // Esta tabla la toma la clase llamadora para su despliegue
           
       }
     }

   }
}

 


Fichero con el código de ejemplo: canchala_FormulasDinamicas.zip - 13 KB


ir al índice