Найти тему

ООП для ПЛК. Codesys и "Стратегия"

Оглавление
Стратегия  — это поведенческий паттерн проектирования, который определяет семейство схожих алгоритмов и помещает каждый из них в собственный класс, после чего алгоритмы можно взаимозаменять прямо во время исполнения программы.

Вот такое определение мы скопируем и вставим, чтобы начать наше повествование. И уже после прочтения определения закрадывается мысль, а как на ПЛК можно в ООП? По факту легко. И очень много подобных паттернов можно переложить на рельсы промышленного программирования.

Для реализации этого безумства нам потребуется Codesys 3.x ибо он немного, да научился в ООП. Преступим.

РЕАЛИЗАЦИЯ

Что нам предлагают умные статьи в интернетах?

Паттерн Стратегия предлагает определить семейство схожих алгоритмов, которые часто изменяются или расширяются, и вынести их в собственные классы, называемые стратегиями .
Вместо того, чтобы изначальный класс сам выполнял тот или иной алгоритм, он будет играть роль контекста, ссылаясь на одну из стратегий и делегируя ей выполнение работы. Чтобы сменить алгоритм, вам будет достаточно подставить в контекст другой объект-стратегию.
Важно, чтобы все стратегии имели общий интерфейс. Используя этот интерфейс, контекст будет независимым от конкретных классов стратегий. С другой стороны, вы сможете изменять и добавлять новые виды алгоритмов, не трогая код контекста.

Интерфейс

Интерфейс, согласно документации Codesys,- это средство объектно-ориентированного программирования. Объект ITF("Интерфейс") описывает набор прототипов методов и свойств. В этом контексте прототип означает, что методы и свойства содержат только объявления и не содержат реализации.

Это значит, что в интерфейсе мы описываем методы. Даем им имена, перечень входных и выходных данных, но никак не трогаем реализацию.

Создание интерфейса
Создание интерфейса

Для создания интерфейса жмем ПКМ->Добавление объекта->Интерфейс, далее задаем ему имя. У меня это будет "StrategyInt".

Затем добавляем метод. Назовем его GetSTR. Для добавления также правая кнопка мыши и добавить метод интерфейса.

Прописываем там лишь одну выходную переменную.

Описание переменных метода интерфейса.
Описание переменных метода интерфейса.

Теперь, когда мы будем создавать функциональные блоки, наследуемые от этого интерфейса, то в нем мы уже будем иметь метод GetSTR с выходной переменной OUT.

Контекст

Это тот функциональный блок, который и будет у нас вызывать различные "стратегии".

Создаем обычный функциональный блок.

Функциональный  блок, который играет роль контекста.
Функциональный блок, который играет роль контекста.

На вход функционального блока мы можем отправить любой объект, который будет унаследован от интерфейса StrategyInt. В реализации мы видим. что при вызове данного функционального блока, мы будем взывать метод GetSTR,а результат возвращать в выходную переменную Result.

Стратегии

Следующий шаг - реализация стратегий. Для начала сделаем две. Они не будет ничем отличаться кроме как возвращать разные значения.

Создаем функциональный блок и наследуем его от нашего интерфейса.

Окно создания функционального блока.
Окно создания функционального блока.

Имя можете указать любое, у меня просто кончилась фантазия.

Я создал два таких блока, которые и будут играть роль наших стратегий.

Созданные стратегии
Созданные стратегии

В каждом есть два метода, реализацию которых необходимо написать.

реализация первой стратегии
реализация первой стратегии
реализация второй стратегии.
реализация второй стратегии.

Да можно напрямую возвращать значения через метод, но я так не хочу.

СБОРКА

А теперь собираем это все вместе.

Сборка всех компонентов.
Сборка всех компонентов.

Я тут немного разбил по шагам. Для реализации нам понадобится. Объект, который играет роль контекста - 1 шт. Наши стратегии. Тут я их включил в блок переменных, но можно и сделать указатель на объект нужной нам стратегии, а уже в коде создать через __NEW.

Ну и переменные Out_1 и Out_2 для наглядности.

Код работаем следующим образом. На первом шаге мы даем на вход MyProc переменной Object нашу стратеги POU_1. Затем происходит вызов контекста и он отрабатывает, записывая результат своей работы в переменную Out_1.

Затем мы даем на вход того же контекста стратегию POU_2, с последующим выводом, результат пишется в переменную Out_2.

Включаем эмуляцию.

Результат выполнения.
Результат выполнения.

Таким образом можно разносить логику работы объектов, которые похожи, но немного отличаются в реализации. Возврат строковой переменой тут просто для примера)