En la primera parte, traté de mostrar que existe un gato negro de OOP en una habitación oscura de lenguajes gráficos, incluso si no es un gato, sino un gato medio muerto del desollador Schroedinger, es decir, no lo es. Se mostró un ejemplo de la implementación de la metodología de programación orientada a objetos, cuando un programa no es código C ++ o Java, sino un diagrama Simulink, SimInTech, SimulationX o SCADE Esterel, cualquier notación gráfica de la descripción del algoritmo.
En los materiales publicitarios, Matlab Simulink a menudo usa el término MOS: diseño basado en modelos. En muchos textos, enfatizan que el diagrama gráfico del algoritmo es un modelo, lo cual, por supuesto, es cierto. Sin embargo, en la definición inicial de MOS, el modelo es principalmente el modelo del objeto para el que se desarrolla el sistema de control, incluido el software de control. Aquí se describe más metodología MOS. Por lo tanto, cuando se desarrolla un sistema de control de acuerdo con la metodología MOS, es posible y necesario utilizar la metodología OOP para el desarrollo de software de gestión. Y para cerrar completamente el problema con los modelos, aquí hay una imagen con las diferencias de uno con el otro. Si todo está claro, entonces ya no puedes leer.

Volvamos a los lenguajes gráficos y POO aplicados a los programas de control para la industria. El lenguaje de programación gráfico proporciona un registro de programa en forma de diagrama de un conjunto de bloques conectados por líneas de comunicación. Como regla, en la programación industrial, un generador de código automático crea un código para el compilador y la carga posterior en el equipo de destino a partir de un circuito gráfico.
Como parte de mi especialidad, tuve que trabajar con el software de gestión para centrales nucleares donde está prohibido utilizar C ++ con estándares de seguridad, solo C puro y, en algunos casos, ni siquiera C, sino lógica "de hierro", donde los algoritmos se implementan como circuitos electrónicos en transistores y relé Y la observancia de los estándares es monitoreada por mucha gente de supervisión severa.

Pero aquí, no importa cuán sorprendente pueda sonar, el desarrollo sigue utilizando la metodología OOP. Porque cuando no puedes usar OOP, pero realmente quieres, puedes hacerlo. Es cierto, entonces todo debe ser devuelto, y eso no sería ningún C ++ y el código final, por seguridad y über alles estándares. Como dicen, comer un pez y no sentarse a cometer violaciones.
Para crear un objeto real mediante la definición de OOP, vinculamos las estructuras de datos y los esquemas de procesamiento en un solo objeto, esto se denomina encapsulación. Y como no podemos usar C ++ para sistemas NPP confiables, debemos analizar todo esto al generar el código. Como se explicó en los comentarios al artículo anterior, el primer compilador C ++ Front funcionó de la misma manera, tradujo el código OOP C ++ a puro C.
En la primera versión de la implementación de OOP en un lenguaje gráfico, creamos un bloque especial que contiene un esquema de cálculo gráfico. Durante la inicialización, este bloque vincula el esquema de clase (método) a una "instancia de clase" específica, un conjunto de variables nombradas de una manera especial.
Considere la segunda realización de la metodología OOP en lenguajes de programación gráficos. La figura 1 muestra el funcionamiento del algoritmo de procesamiento del sensor.

Figura 1. Programa de procesamiento del sensor.
Este es un método de clase. Corresponde a su propia categoría "Sensores" en la base de datos: una clase abstracta con un conjunto dado de campos y una instancia del sensor específico de clase KBA31CFO1 . Para este sensor, los campos tienen valores específicos, algunos de los campos son establecidos por el usuario, algunos de los campos se calculan durante la ejecución del programa. ver foto 2

Figura 2. La base de datos de señales con la categoría abierta "Sensor".
Hasta ahora, todo es como en la primera realización, donde formamos la unión del esquema de diseño a un sensor específico al instalar la unidad en el circuito. "¿Dónde está la diferencia?" - usted pregunta Y la diferencia está dentro del bloque. Si en la primera versión había un diagrama de diseño dentro, que se copió con cada instalación del bloque, entonces en esta versión el interior se ve así:

Figura 3. Los interiores de una instancia de bloque de una instancia de clase.
En lugar del esquema de diseño, solo la "transmisión y recepción de datos" se "muestran" dentro del bloque.
Y el cálculo en sí se lleva a cabo en otro lugar, en el diagrama de la Figura 1. En algunos casos, es posible no usar bloques en absoluto en el diagrama de cálculo, es suficiente tener instancias de la clase de sensor en la base de datos de singles. Esta es la segunda forma de implementar la encapsulación en lenguajes gráficos. El truco es que todos los bloques en el diagrama de la Figura 1 son vectoriales y no procesan una sola señal, sino un vector de señales de todos los sensores de este tipo en el esquema de cálculo. Si habilita el modo de mostrar los resultados en la línea de comunicación, veremos que cada línea de comunicación contiene no un dígito, sino un vector de 4 números (por el número de sensores en la base de datos).

Figura 4. Diagrama de procesamiento de la señal de los sensores en el modo de visualización de valores.
Por lo tanto, un esquema de procesamiento implementa el procesamiento de todos los sensores en el proyecto, y cada sensor se procesa con sus propios parámetros especificados en la base de datos como las características de una instancia particular de la clase. Por ejemplo, el limitador toma el valor máximo de la base de datos, que se establece igual para los primeros tres sensores y difiere para el cuarto. (ver figura 5)

Figura 5. Parámetros del bloque limitador en el esquema de cálculo.
Y qué pasa con el código resultante, que se genera automáticamente de acuerdo con este maravilloso esquema, ¿cómo se las arregla para evitar los artefactos OOP? Es simple: no hay trampa ni OOP, C pura en el código. Para cada bloque del esquema de procesamiento de vectores, se formará un ciclo que proporcione tantos cálculos como instancias de clase en el proyecto. En nuestro caso, hay 4 sensores, por lo que primero formamos matrices de dimensión "4" leyendo las señales de los sensores:
}; state_vars->kbastdv104_out_0_[0] = kba31cf001_mf_type; state_vars->kbastdv104_out_0_[1] = kba32cf001_mf_type; state_vars->kbastdv104_out_0_[2] = kba33cf001_mf_type; state_vars->kbastdv104_out_0_[3] = uf40y329084320_mf_type
Luego ordenamos todos los bloques en orden y los ejecutamos en un bucle. Para cada elemento de una matriz de tipo, cada bloque de cálculos se realizará para todos los sensores.
for(i=0;i<4;i++){ locals->v211_out_0_[i] = state_vars->kbastdv125_out_0_[i] && (!(locals->v191_out_7_[i] > 0.5)); locals->v209_out_2_[i] = consts->kbastdv121_a_[i]*state_vars->kbastdv127_out_0_[i]; locals->v209_out_3_[i] = (1)*consts->kbastdv122_a_[i]+(1)*locals->v209_out_2_[i]; … }
Después del cálculo, registramos las señales para cada instancia de la clase:
kba31cf001_mf_xb01 = state_vars->kbastdv207_out_0_[0]; kba32cf001_mf_xb01 = state_vars->kbastdv207_out_0_[1]; kba33cf001_mf_xb01 = state_vars->kbastdv207_out_0_[2]; uf40y329084320_mf_xb01 = state_vars->kbastdv207_out_0_[3];
Como puede ver, no hay objetos en el código final. SI limpio, inocente y seguro. En el ejemplo anterior, la implementación de OOP en un lenguaje gráfico, un circuito vectorial calcula todos los sensores del mismo tipo. Esta técnica le permite cambiar un esquema para cambiar el procesamiento de todos los sensores.
Otro beneficio adicional de este enfoque es el seguro contra errores. Imagínese: agrega manualmente un sensor y en un lugar olvidó aumentar el número de repeticiones durante el procesamiento en un ciclo. Ningún analizador de código estático podrá detectar este error, el código es correcto. E incluso en el trabajo, esto puede no afectar de manera inmediata y obvia.
Bueno, al final, el prometido polimorfismo y herencia. En el primer método, el usuario recibió muchos esquemas idénticos, que pudo editar después de instalar el bloque de submodelo y, por lo tanto, llevar a cabo el polimorfismo, cambiando el comportamiento de una instancia particular de la clase. Creo que todos adivinaron que es posible cambiar el esquema de procesamiento para un sensor en particular, y obtendremos una nueva clase que tiene los mismos campos, pero los métodos son diferentes. También puede agregar nuevos campos y obtener una nueva clase con diferentes campos que contengan todos los campos del padre y los métodos del padre.
La Figura 6 muestra un ejemplo de dos bloques de las clases "padre" y "heredero". Dentro del bloque, se guarda el esquema de cálculo de la clase principal. Todos los datos van a un bloque vectorial común, similar al bloque de la Fig. 4. El método de clase padre se repite completamente. Y luego la clase sucesora tiene un campo adicional Yatm y un recálculo adicional del valor utilizando el bloque de interpolación lineal.
Por lo tanto, sigue siendo posible cambiar los métodos de procesamiento del padre, que cambiará en todos los herederos de las clases, así como personalizar individualmente el comportamiento del heredero.

Figura 6. Polimorfismo en herederos de clase.
Para resumir, podemos argumentar que la metodología OOP puede usarse para crear software en lenguajes de programación gráficos. Abstracción, encapsulación, herencia, polimorfismo: todos estos principios se implementan fácil y naturalmente con las herramientas de desarrollo adecuadas. Es importante tener en cuenta que el código final, después de la generación automática a partir de un lenguaje gráfico, permanece completamente seguro C sin ningún OOP
En algunos casos, el resultado del desarrollo de software de control en forma gráfica no es el código C para cargar en los controladores, sino el diagrama de circuito "lógica de hierro", pero la técnica descrita anteriormente OOP también funciona bien.