Часть 4. Malleable Vis и их применение в LVOOP.
Спасибо за обратную связь и приведенные ссылки, по которым я получил хороший материал для анализа. Итак, нововведение Malleable vi. Рассмотрим, что это такое, как эта технология может помочь в LVOOP. О самой технологии:
Malleable vi – позволяет создавать виртуальные приборы, у которых входные терминал являются адаптивными. Это позволяет подавать на входы .vi данные любого типа, но работоспособность будет определяться возможностью обработать эти данные.
Профит: позволяет иметь 1 .vi для выполнения однотипных задач для разных типов данных. Сразу пример, который приводится в LV библиотеке примеров:
Malleable vi для выделения последнего элемента из массива с такой реализацией:
Входы-выходы у нас типа variant, но реализация заточена для строго определенной структуры данных – одномерный массив. Другое дело, что элементами этого массива могут быть числа, буквы, кластеры и т.д. Так же хочу отметить Type Specialization структуру:
- 1.png (2.43 КБ) 3175 просмотров
Она позволяет переопределить логику выполнения кода в зависимости от входного типа/структуры данных и в сочетании с Malleable vi позволяет строить приборы без высокой степени вложенности и более гибкие. По своей природе Malleable vi реализует полиморфную функцию, однако возникает резонный вопрос: чем отличаются полиморфные vi от этих самых Malleable vi в LabVIEW? Первое и самое очевидное – это способ создания и использования. Нам не нужно забоится о паттерне самого прибора(connector pane patterns). Мы можем описать логику/случай внутри Type Specialization-структуры, а для полиморфного vi нам потребуется создать отдельный прибор с реализацией и включением его в качестве экземпляра в коллекцию полиморфных приборов. Отдельным пунктом в преимуществах Malleable vi стоит использование их с классами, поскольку эти приборы способны адаптировать вход типа данных.
Ранее возникал вопрос о множественном наследование и интерфейсах, мол что делать в этом случае в LabVIEW.
Итак, я ознакомился с презентацией от Piotr Kruczkowski(Integration Engineering Services - Software Architect). Презентацию можете найти по этой ссылке(под сообщением прикреплены файлы):
https://forums.ni.com/t5/LabVIEW-Archit ... -p/3804592
В ней говорится о пяти основных рекомендациях в ООП (аббревиатура SOLID) и, в особенности, о реализации пятого принципа(DIP) в LabVIEW – инверсия зависимостей, которая призвана уменьшить взаимосвязанность программных модулей. Про SOLID в том или ином виде рассказывают многие книги по ООП и паттернам проектирования. Я бы сказал, что в паттернах проектирования это раскрывается гораздо сильнее. Кроме SOLID существую и другие рекомендации, которые рассматриваются в более углубленном курсе объектно-ориентированного проектирования.
Кратко:
D — Dependency inversion principle — Принцип инверсии зависимостей: зависимости внутри системы строятся на основе абстракций. Модули верхнего уровня не зависят от модулей нижнего уровня. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Возьмем ситуацию, когда объект класса A вызывает методы объекта класса B, значит A зависит от B. С применением этого принципа, объект типа B должен быть инстанциирован вне A и передан как зависимость в A. Говоря проще, мы должны создать интерфейс, через который объект А будет использовать объект В.
Возвращаемся к презентации. Piotr Kruczkowski предлагает использовать подход мутации классов(class mutation mechanism). Термин придуман самим автором наверно, потому что описание этого термина в других источниках я не нашел. Реализация некого интерфейса выполнена с помощью наследования и дружественных классов. В проекте классы MeasA и ViewA унаследованы от IMeasurement и IView, а в качестве описания объекта содержат объект класса А; также эти 2 класса объявлены друзьями для класса А. После этих прелюдий демонстрируется возможность использования классом А и его наследником функции классов MeasA и ViewA в духе интерфейса:
Реализуется ли инверсия зависимости в данном примере? Да, реализуется, за счет использования абстрактных методов, наследования и прослойки в виде классов. Мутация заключается в том, что классы MeasA и ViewA в качестве объекта используют объект класса А, для которого они являются друзьями.
Так же я рассмотрел примеры использования Malleable vi в классах. Начиная с 2017-ой версии SP1 эти приборы поддерживают адаптацию выходов для объектов класса. Идея с созданием отдельного класса с Malleable vi или просто отдельно Malleable vi с набором методов кажется привлекательной. Итак, мы имеем базовый класс с набором абстрактных методов. Положим, что часть этих методов необходимо вызывать в разных несвязных классах. Создаём отдельные наборы методов как Malleable vi и на вход будем подавать кластер из объектов. Внутри Type Specialization структуры будем вызывать нужный метод для текущего объекта. В этом случае потребуется дополнительно вести внятную иерархию проекта и имён тех самых Malleable vi-интерфейсов, чтобы не запутаться, кто кому что предоставляет. И опять же вся хитрость будет сводиться к созданию одного объекта класса внутри другого объекта класса для вызова его метода. Аналогично, как это делается и в мутации, когда объектом одного класса является объект другого класса и они там по ходу выполнения переопределяются где нужно. Только в случае Malleable vi будем определять вызов метода внутри Type Specialization и это может помочь привести к некоторому однообразию и визуальной понятности.
Заключение: отсутствие интерфейсов/множественного наследования приводят к тому, что приходится заниматься фокусами и вырабатывать собственный стиль либо придерживаться некого корпоративного подхода.
Пока что я выработал единственно правильный подход для LVOOP: Базовые абстрактные классы со своими детьми(конкретными реализациями объектов) и максимальная независимость одного базового класса от другого. Если возникает ситуация, что один независимый класс нуждается в исключительном методе другого класса – проще реализовать его внутри нуждающегося класса. Если же такую реализацию требует десяток объектов, имеет смысл вынести метод в базовый класс и наследовать от него эту реализацию, либо использовать Malleable vi.