Ir al contenido principal

Herencia y redefinición de métodos


Pepito, el arquitecto de software que vive en mi cabeza, ha irrumpido en mi pensamiento vociferando - ¡ Esto es insostenible !

Al parecer ha clonado nuestro bonito proyecto y ha encontrado flagrantes fallos de diseño. He tratado de explicarle que tenía muchas ganas de sacar adelante las primeras versiones, que las cosas no salen perfectas a la primera, le he reconocido que hay margen de mejora, y que tengo varias cosas apuntadas en mi libreta para retocar. Él seguía enfurecido. - ¡ No puedes enseñar esto al público, qué van a pensar !

En la eterna pugna entre desarrollador y arquitecto, siempre el arquitecto tiene la razón (¿o no? jjj)

Me encantaría que fueran Uds. mismos queridos lectores quienes me propusieran mejoras y alternativas para la plataforma de test, lamentablemente este blog es de muy reciente creación, y no creo que ello vaya a ocurrir, así que de momento nos arreglaremos Pepito y yo solos. No obstante les animo una y otra vez a participar activamente.

Recuerden que disponen del proyecto completo en GitHub
Enigma Software - ZM LABS

Uso correcto de la herencia y la suplantación de métodos.

Cada uno de los Test que definamos van a constituir una clase, con su lógica particular. Pero hemos definido una clase base para cada uno de los test, que contará con el método Start() y las propiedades Estado y Mensajes.

En el objeto test_object.ExecutionProperties hemos definido una propiedad genérica de tipo Object para asociar la clase asociada al test seleccionado. Sin embargo, estábamos asociando la clase derivada, en este caso test1_multithreading_vs_singlethreading, lo que nos obligaba a usar la cláusula CASE para saber a que tipo de dato corresponde la propiedad.

En lugar de esto, la mejor opción en asociar a la propiedad genérica la clase base a la que hemos llamado test_exec

La asignación de la propiedad genérica queda igual que estaba:

_treeelem.TestObject.execution.OBJ = test_types.GetObject(_test_functions, _type);

..pero modificamos el método GetObject para instanciar un objeto del tipo base test_exec y su correspondiente clase derivada.

        public static Object GetObject(test_functions _functions, ZmLabsObjects.enumTestTypes _type)
        {
            test_exec res = new test_exec(_functions);

            switch (_type)
            {
                case ZmLabsObjects.enumTestTypes.test1_multithreading_vs_singlethreading:

                    res = new test1_multithreading_vs_singlethreading(_functions);
                    break;

            }

            return res;
        }

Poca diferencia, pero trascendente, ya que a la hora de ejecutar el test ya no necesitamos hacer un SWITCH según el tipo de objeto instanciado como antes, sino que invocamos el método virtual Start() sea cual sea la clase derivada:

        public static void HiloNegocio()
        {
            var negobject = (test_exec)_testobject.execution.OBJ;
            negobject.Start();

            //switch (_testobject.execution.TestType)
            //{
            //    case enumTestTypes.test1_multithreading_vs_singlethreading:

            //        var obj2 = (test1_multithreading_vs_singlethreading)_testobject.execution.OBJ;
            //        obj2.Start();

            //        break;
            //}
        }

Del mismo modo, en la lectura de las propiedades Estado y Mensajes ya no es necesario dicho SWITCH que evaluaba el tipo de test que se estaba ejecutando, sino que leemos las propiedades de la clase base, heredadas por la clase del test específico:

            test_exec execObject = (test_exec)_testobject.execution.OBJ;

            _estadoProceso = execObject.Estado;

            lstMensajes = execObject.Mensajes.Where(msg => msg.leido == false).ToList();

            foreach (var msg in lstMensajes)
            {
                execObject.SetMsgLeido(msg.id);
            }

            //_testobject.execution.OBJ = execObject;

            //switch (_testobject.execution.TestType)
            //{
            //    case enumTestTypes.test1_multithreading_vs_singlethreading:

            //        var obj2 = (test1_multithreading_vs_singlethreading)_testobject.execution.OBJ;

            //        _estadoProceso = obj2.Estado;
            //        lstMensajes = obj2.Mensajes.Where(msg => msg.leido == false).ToList();

            //        foreach (var msg in lstMensajes)
            //        {
            //            obj2.SetMsgLeido(msg.id);
            //        }

            //        _testobject.execution.OBJ = (test1_multithreading_vs_singlethreading)obj2;

            //        break;
            //}

Una de las ventajas de la herencia es la posibilidad de reutilizar métodos genéricos en todas las clases derivadas, y aquí tenemos un ejemplo magnífico. Se trata del método SetMsgLeido. En este momento el método en cuestión se encuentra implementado en la clase derivada test1_multithreading_vs_singlethreading. Ello nos obligaría a repetir esta funcionalidad en cada uno de los test. Ahora por orden de Pepito voy a trasladar el método a la clase base test_exec, de modo que se convertirá en un método reutilizable en todas las clases derivadas test1_, test2_, etc.

Les mostraré pues como han quedado las clases base y derivada:

    public class test_exec
    {
        public test_types.enumEstadoProceso Estado;

        public List<test_types.mensajes> Mensajes = new List<test_types.mensajes>();
        public test_functions _testobject;

        public test_exec(test_functions p_testobject)
        {
            _testobject = p_testobject;
        }

        public virtual void Start() {  }

        public void SetMsgLeido(Guid id)
        {
            Mensajes.Where(idx => idx.id == id).First().leido = true;
        }

        private void SetMsg(string Msg)
        {
            this.Mensajes.Add(new test_types.mensajes()
            {
                id = Guid.NewGuid(),
                mensaje = Msg,
                leido = false
            });
        }
    }

    public class test1_multithreading_vs_singlethreading : objects.test_exec
    {
        public static List<objects.process_control> _lst_process_control = new List<objects.process_control>();

        public test1_multithreading_vs_singlethreading(test_functions p_testobject) : base(p_testobject) { }

        public override void Start()
        {
            this.Estado = test_types.enumEstadoProceso.Ejecutando;

   //-->> cosas

            this.Estado = test_types.enumEstadoProceso.Finalizado;

        }

        #region Cases

        public TestCases MultithreadingCase(TestCases _test)
        {
   //-->> cosas
        }

        private static void CalcFibo1(int index)
        {
   //-->> cosas
        }

        public TestCases SinglethreadingCase(TestCases _test)
        {
   //-->> cosas
        }

        public TestCases HybridCase(TestCases _test)
        {
   //-->> cosas
        }

        private static void CalcFibo2(int index)
        {
   //-->> cosas
        }

        #endregion
    }

Recuerden amigos dejar cuantos comentarios les parezcan oportunos.




Comentarios

Entradas populares de este blog

Test 3: ¿Son eficientes los ORMs?

Bienvenidos amigos. Me complace anunciar que por fin estrenamos la categoría " SQL Server Tips ", y lo hacemos por todo lo alto, entrando de lleno en un aspecto altamente polémico entre programadores. ¿Es eficiente un ORM en los accesos a datos? Ya conocen la filosofía de nuestros Tests, no vamos a teorizar demasiado, pero sí una pequeña base va a ser necesaria para conseguir una buena respuesta a nuestra pregunta. He leído un interesante  artículo de nuestros súper amigos de Deloitte ( cuando usar ORM ) argumentando que el uso o no de un ORM hay que decidirlo en relación a la complejidad de nuestro modelo de datos, y al rendimiento que requeriremos en nuestras soluciones, pero, ¿cuándo no deseamos el mejor rendimiento para nuestro software? Lo cierto es que, como ya hemos visto, el ORM facilita mucho las cosas, aporta claridad al código, de eso no cabe duda, pero, ¿es eficiente? He ahí la cuestión. Sobre este asunto vamos a poner a funcionar nuestros apreciados Test. C

Proyecto GEOW. Implementando el patrón CQRS. 2ª parte

En el anterior post ( Proyecto GEOW. Implementando el patrón CQRS ) nos adentramos en el funcionamiento del proyecto GEOW que nos va a servir de base para implementar un patrón arquitectónico, CQRS , pensado para dar respuesta a sistemas con alta exigencia de lecturas y escrituras simultáneas. Para ello hemos creado una interfaz gráfica con una serie de figuras geométricas en movimiento. Ahora vamos a ir a la parte de EL DATO. Cada vez que uno de estos cuadrados cambia de posición envía una trama con sus propias características, y sus nuevas coordenadas. Cada uno de los cuadrados realiza un movimiento cada 300 milisegundos, y he llegado a probar con hasta unas 700 figuras. En estos niveles el software empieza a sufrir, pero más la parte gráfica. Aparentemente el sistema de grabación de coordenadas se mantiene en buena forma. Vamos a ver, precisamente, este sistema de grabación: Grabando lotes de coordenadas en BBDD En el objeto PointObj que representa cada una de las figuras, en el

Primeros pasos en Enigma Software Labs

En pocas palabras: vamos a probar y estresar distintas soluciones de software para un mismo problema, en busca de realidades matemáticas. Para ello, lo primero que necesitamos en averiguar el modo de publicar código aquí en Blogger . Para ello voy a usar un sistema súper sencillo y eficiente. Ahí va un ejemplo de código C# private void frmMonitor_Load ( object sender, EventArgs e) { TreeNode _tr = new TreeNode( "SQL Server Tips" ); TreeNode _tr2 = new TreeNode( "C# Code" ); treeCatalogo.Nodes.Add(_tr); treeCatalogo.Nodes.Add(_tr2); //splitContainer.Panel1.Focus(); //lstMonitor.Focus(); } Hilarante ¿verdad?   hilite.me  lo hace posible. Bien, paso 2, fácil y sencillo: vamos a crear una plataforma de testeo para C# en una bonita solución que compartiré en el repositorio GIT, para disfrute de todos. Enigma Software - ZM LABS Como posteriormente me dive