POO em linguagens de programação gráfica. Parte 2 MOS e OOP

Na primeira parte, tentei mostrar que existe um gato POO preto em uma sala escura de linguagens gráficas, mesmo que não seja um gato, mas um gato meio morto do estripador Schroedinger, ou seja, não é. Um exemplo da implementação da metodologia de programação orientada a objetos foi mostrado, quando um programa não é código C ++ ou Java, mas sim um diagrama Simulink, SimInTech, SimulationX ou SCADE Esterel - qualquer anotação gráfica da descrição do algoritmo.


Em materiais de publicidade, o Matlab Simulink costuma usar o termo MOS - Design baseado em modelo. Em muitos textos, eles enfatizam que o diagrama gráfico do algoritmo é um modelo, o que, é claro, é verdadeiro. No entanto, na definição inicial de MOS, o modelo é principalmente o modelo do objeto para o qual o sistema de controle é desenvolvido, incluindo o software de controle. Mais metodologia MOS é descrita aqui. Assim, ao desenvolver um sistema de controle de acordo com a metodologia MOS, é possível e necessário usar a metodologia OOP para o desenvolvimento de software de gerenciamento. E, para fechar completamente o problema com os modelos, aqui está uma imagem com as diferenças de um e de outro. Se tudo estiver claro, você não poderá mais ler.




Voltemos às linguagens gráficas e ao POO, aplicados aos programas de controle da indústria. A linguagem de programação gráfica fornece um registro de programa na forma de um diagrama a partir de um conjunto de blocos conectados por linhas de comunicação. Como regra, na programação industrial, um código para o compilador e subsequente carregamento no equipamento de destino é criado a partir de um circuito gráfico por um gerador de código automático.


Como parte da minha especialidade, tive que trabalhar com o gerenciamento de software para usinas nucleares, onde é proibido usar C ++ com padrões de segurança, apenas C puro e, em alguns casos, nem C, mas lógica "ferro", onde os algoritmos são implementados como circuitos eletrônicos em transistores e revezamento. E a observância dos padrões é monitorada por supervisores duros.



Mas aqui, por mais surpreendente que pareça, o desenvolvimento ainda está usando a metodologia OOP. Porque quando você não pode usar OOP, mas realmente deseja, pode. É verdade que tudo precisa ser devolvido de volta, e isso não seria nenhum C ++ e o código final, para os padrões de segurança e über alles. Como se costuma dizer, comer um peixe e não se sentar por violações.


Para criar um objeto real pela definição de OOP, ligamos estruturas de dados e esquemas de processamento em um único objeto, isso é chamado de encapsulamento. E como não podemos usar C ++ para sistemas NPP confiáveis, precisamos analisar tudo isso ao gerar o código. Conforme explicado nos comentários do artigo anterior, o primeiro compilador C ++ Front funcionou da mesma maneira, ele traduziu o código OOP C ++ em C. puro


Na primeira versão da implementação do OOP em uma linguagem gráfica, criamos um bloco especial contendo um esquema de cálculo gráfico. Durante a inicialização, esse bloco vinculou o esquema de classe (método) a uma "instância de classe" específica - um conjunto de variáveis ​​nomeadas de uma maneira especial.


Considere a segunda modalidade da metodologia OOP em linguagens de programação gráfica. A Figura 1 mostra a operação do algoritmo de processamento do sensor.



Figura 1. Programa de processamento do sensor.


Este é um método de classe. Corresponde à sua própria categoria "Sensores" no banco de dados - uma classe abstrata com um determinado conjunto de campos e uma instância do sensor específico da classe KBA31CFO1 . Para este sensor, os campos têm valores específicos, alguns dos campos são definidos pelo usuário, outros são calculados pela execução do programa. ver foto 2



Figura 2. O banco de dados de sinal com a categoria aberta “Sensor”.


Até agora, tudo é como na primeira modalidade, onde formamos a ligação do esquema de projeto a um sensor específico ao instalar a unidade no circuito. "Onde está a diferença?" - você pergunta. E a diferença está dentro do quarteirão. Se na primeira versão havia um diagrama de design interno, que era copiado em cada instalação do bloco, nesta versão o interior se parecia com isso:



Figura 3. Os interiores de uma instância de bloco de uma instância de classe.


Em vez do esquema de design, apenas a transmissão e recepção de dados são "mostradas" dentro do bloco.
E o próprio cálculo ocorre em outro lugar, no diagrama da Figura 1. Em alguns casos, é possível não usar blocos no diagrama de cálculo, é suficiente ter instâncias da classe de sensor no banco de dados de singles. Esta é a segunda maneira de implementar o encapsulamento em linguagens gráficas. O truque é que todos os blocos no diagrama da Figura 1 são vetoriais e processam não um sinal, mas um vetor de sinais de todos os sensores desse tipo no esquema de cálculo. Se você ativar o modo de exibição dos resultados na linha de comunicação, veremos que cada linha de comunicação contém não um dígito, mas um vetor de 4 números (de acordo com o número de sensores no banco de dados).



Figura 4. Diagrama de processamento do sinal dos sensores no modo de visualização de valores.


Assim, um esquema de processamento implementa o processamento de todos os sensores no projeto, com cada sensor sendo processado com seus próprios parâmetros especificados no banco de dados como as características de uma instância específica da classe. Por exemplo, o limitador pega o valor máximo do banco de dados, que é definido da mesma forma para os três primeiros sensores e difere para o quarto. (ver fig. 5)



Figura 5. Parâmetros do bloco limitador no esquema de cálculo.


E o código resultante, que é gerado automaticamente de acordo com esse maravilhoso esquema, como você consegue evitar artefatos de OOP? É simples: sem trapaça e sem POO, C puro no código. Para cada bloco do esquema de processamento vetorial, será formado um ciclo que forneça quantos cálculos houver instâncias de classe no projeto. No nosso caso, existem 4 sensores, então formamos matrizes da dimensão "4" lendo os sinais dos sensores:


/* Index=104 UID=104 GeneratorClassName=TSignalReader Name=buz1.sensor.Macro6.Macro3.Macro157.SignalReader3 Type=    */ }; 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 

Depois, ordenamos todos os blocos em ordem e os executamos em um loop. Para cada elemento de uma matriz do tipo, cada bloco de cálculos será realizado para todos os sensores.


 /* Index=211 UID=211 GeneratorClassName=TAndSrc Name=buz1.sensor.Macro6.And61 Type=  */ for(i=0;i<4;i++){ locals->v211_out_0_[i] = state_vars->kbastdv125_out_0_[i] && (!(locals->v191_out_7_[i] > 0.5)); /* Index=212 UID=212 GeneratorClassName=TMulDbl Name=buz1.sensor.Macro6.Mul_oper1 Type= */ locals->v209_out_2_[i] = consts->kbastdv121_a_[i]*state_vars->kbastdv127_out_0_[i]; /* Index=213 UID=213 GeneratorClassName=TSumSrc Name=buz1.sensor.Macro6.Add_oper1 Type= */ locals->v209_out_3_[i] = (1)*consts->kbastdv122_a_[i]+(1)*locals->v209_out_2_[i]; … } 

Após o cálculo, registramos os sinais para cada instância da classe:

 /* Index=776 UID=776 GeneratorClassName=TSignalWriter Name=buz1.sensor.Macro6.Macro3.SignalWriter4 Type=    */ 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 você pode ver, não há objetos no código final. SI limpo, inocente e seguro. No exemplo acima, a implementação do OOP em uma linguagem gráfica, um circuito vetorial calcula todos os sensores do mesmo tipo. Essa técnica permite alterar um esquema para alterar o processamento de todos os sensores.


Outro benefício adicional dessa abordagem é o seguro contra erros. Imagine: você adiciona manualmente um sensor e em um lugar esquece de aumentar o número de repetições durante o processamento em um ciclo. Nenhum analisador de código estático será capaz de detectar esse erro, o código está correto. E mesmo no trabalho, isso pode não afetar imediatamente e de maneira óbvia.


Bem, no final, o prometido polimorfismo e herança. No primeiro método, o usuário recebeu muitos esquemas idênticos, que ele poderia editar após instalar o bloco de submodelo e, assim, executar o polimorfismo, alterando o comportamento de uma instância específica da classe. Acho que todo mundo imaginou que é possível alterar o esquema de processamento de um sensor em particular, e teremos uma nova classe com os campos correspondentes, mas os métodos são diferentes. Você também pode adicionar novos campos e obter uma nova classe com campos diferentes, contendo todos os campos do pai e os métodos do pai.


A Figura 6 mostra um exemplo de dois blocos das classes "pai" e "herdeiro". Dentro do bloco, o esquema de cálculo da classe pai é salvo. Todos os dados vão para um bloco vetorial comum, semelhante ao bloco na Fig. 4. O método da classe pai é completamente repetido. E a classe sucessora possui um campo Yatm adicional e um recálculo adicional do valor usando o bloco de interpolação linear.


Assim, continua sendo possível alterar os métodos de processamento do pai, que serão alterados em todas as classes-herdeiros, bem como personalizar individualmente o comportamento do herdeiro.



Figura 6. Polimorfismo em herdeiros de classe.


Para resumir, podemos argumentar que a metodologia OOP pode ser usada para criar software em linguagens de programação gráfica. Abstração, encapsulamento, herança, polimorfismo - todos esses princípios são fácil e naturalmente implementados pelas ferramentas de desenvolvimento corretas. É importante observar que o código final, após a geração automática a partir de uma linguagem gráfica, permanece puro C seguro sem qualquer OOP


Em alguns casos, o resultado do desenvolvimento de software de controle em forma gráfica não é o código C para carregar nos controladores, mas o diagrama de circuitos “lógica lógica”, mas a técnica descrita acima OOP também funciona muito bem.

Source: https://habr.com/ru/post/pt454232/


All Articles