Объектно-ориентированное программирование (ООП) в MQL5
Введение
В этой статье мы поделимся одной из самых важных тем в программировании, облегчающую написание кода и позволяет применить принцип DRY (Do Not Repeat Yourself, не повторяйся) разработчикам и программистам. Кроме того, помимо прочего повышается безопасность любого созданного программного обеспечения. Мы поговорим об объектно-ориентированном программировании (ООП) и о том, как мы можем использовать эту концепцию при работе с MQL5 (MetaQuotes Language).
Итак, мы раскроем эту интересную и важную тему в следующих разделах:
Основная цель этой статьи — дать понимание основ объектно-ориентированного программирования (ООП) в целом и того, как оно может быть использовано при создании программного обеспечения. Мы узнаем, как можно применить этот подход в MQL5 для создания более эффективных и безопасных программ.
При необходимости вы можете найти информативные ресурсы об этом подходе, тем более что он применим в других языках программирования, таких как C++, Java, Python и других. Всю необходимую информацию о языке MQL5 можно найти в официальной документации.
Что такое ООП?
Начнем с определения ООП. ООП помогает создавать и разрабатывать повторно используемое программное обеспечение без дублирования работы и кода с применением концепции DRY (не повторяйся).
ООП помогает нам приблизиться к природе мира, потому что объекты окружают нас повсюду в повседневной жизни. Мы будем иметь дело с объектами и классами, объект означает экземпляр класса, а класс — это шаблон для объекта. Внутри шаблона, который является классом, мы подробно определяем поведение объекта.
Основные понятия ООП:
При использовании ООП в разработке применяются следующие принципы.
- Инкапсуляция.
- Абстракция.
- Наследование.
- Полиморфизм.
1. Инкапсуляция:
Инкапсуляция — метод, который позволяет связать функции и данные в одном классе, данные и функции в классе могут быть приватными - доступными только внутри класса, или публичными - доступными вне класса. Инкапсуляция помогает скрыть сложность реализации класса и дает разработчику полный контроль над своими данными, помогая отслеживать все зависимые значения без конфликтов.
Инкапсуляция позволяет поддерживать работоспособность нашей системы и избегать множества возможных ошибок, а также обеспечивает высокий уровень контроля для разработчика и упрощает тестирование и обработку данные классов, не затрагивая и не изменяя весь код программного обеспечения. Она также помогает устранять ошибки и упрощает код.
Следующий рисунок описывает понятие инкапсуляции:
2. Абстракция:
Абстракция – это метод скрытия ненужных и представления только существенных деталей. Она шире понятия инкапсуляции, но помогает достичь той же цели: защитить данные и реализовать функции без полного знания о процессе реализации всех классов, а только с пониманием того, что нужно сделать, чтобы реализация была выполнена.
Чтобы достичь этой цели нам нужно включить два важных метода - интерфейс и реализацию. Интерфейс — это метод, который позволяет классам взаимодействовать друг с другом, а реализация — это метод, который содержит все детали кода или логику классов. Таким образом, абстракция помогает повысить безопасность программного обеспечения, а также позволяет не повторять процесс кодирования с нуля, разрабатывая и кодируя больше приложений на основе уже созданных.
3. Наследование:
Судя по названию, концепция наследования означает, что мы получаем новый класс от старого, при этом новый наследует функции старого. В этом случае старый класс называется родительским или суперклассом, а новый производный класс называется дочерним классом. Эта концепция помогает применить концепцию DRY (не повторяйся), при этом сохраняя возможность повторного использования.
4. Полиморфизм:
Полиморфизм позволяет функции обрабатывать данные разных типов. Например, мы можем использовать метод суммирования для получения значений суммы (a) и (b) и другой - для получения суммы (a), (b) и (c).
Проще говоря, полиморфизм означает один интерфейс и множество методов.
Резюмируя, можно сказать, что ООП — это модель программирования, которая фокусируется на организации разработки программного обеспечения с помощью объектов, которые могут иметь уникальное поведение и характеристики. Это полезная модель в больших и сложных программах, особенно если они часто обновляются.
Особенности ООП:
- Программы, применяющие ООП, включают классы и функции.
- Высокий уровень безопасности данных скрывается за счет применения принципов инкапсуляции и абстракции.
- Это упрощает работу над сложными проектами, поскольку код можно разделить на небольшие блоки кода, и это может снизить сложность проекта.
- Процессы обновления и разработки становятся проще.
- Возможность повторного использования кода за счет применения принципа наследования.
- Возможность создавать множество экземпляров одного и того же класса без конфликтов.
Существует множество языков программирования, которые могут применять подход ООП. Наиболее популярными являются C++, C#, Python, Java, JavaScript, PHP и другие. В их число также входит и MQL5.
ООП в MQL5
В этом разделе мы рассмотрим ООП в MQL5 и узнаем, как его использовать.
Перед применением ООП в MQL5, нам нужно понять, как мы можем использовать в MQL5 следующее:
- Классы
- Модификатор доступа
- Конструкторы и деструкторы
- Производные (дочерние) классы
- Виртуальные функции
- Объекты
Классы:
В MQL5, если нам нужно создать класс, который будет образцом объекта, нам нужно объявить этот класс в глобальной области видимости так же, как функции. Мы можем создать этот класс, используя ключевое слово class, за которым следует желаемый уникальный идентификатор, затем внутри фигурных скобок мы можем разместить наши переменные и методы, которые являются членами класса, а затем после второй фигурной скобки мы ставим точку с запятой, чтобы завершить объявление класса. Мы можем использовать это объявление класса в программе или во включаемом файле.
Ниже приведен пример объявления этого класса:
class Cobject { int var1; // variable1 double var2; // variable1 void method1(); // Method or function1 };
Как мы видим в предыдущем примере, у нас есть три члена класса: две переменные и один метод или функция.
Модификаторы доступа:
С помощью этих модификаторов доступа мы можем определить, какие переменные и функции мы можем использовать вне класса, и у нас есть три ключевых слова доступа: public, private и protected.
- Public: члены, которые могут быть доступны для использования вне класса.
- Private: представляет члены, которые не могут быть доступны для использования вне класса, но доступны для использования внутри класса только функциями. Дочерний класс этого класса не будет наследовать эти приватные члены.
- Protected: представляет элементы, которые будут унаследованы дочерними классами, но являются приватными по своей природе.
Ниже представлен пример:
class Cobject { private: int var1; // variable1 protected: double var2; // variable1 public: void method1(); // Method or function1 };
Как мы видим в предыдущем примере, у нас есть три члена в классе с двумя переменными: один является приватным (private), другой - защищенным (protected), а третий - общедоступным (public).
Конструкторы и деструкторы:
Если нам нужно инициализировать переменные в классе, мы используем конструктор. При отсутствии он будет создан компилятором по умолчанию, но по умолчанию не будет виден. Он также должен быть общедоступным. Деструктор — это автоматически вызываемая функция при уничтожении объекта класса. Деструктор можно назвать так же, как имя класса, с тильдой (~). Независимо от того, имеется ли деструктор или нет, строка, динамический массив и объект требуют деинициализации, поэтому они будут деинициализированы в любом случае.
Ниже приведен пример конструктора:
class CPrices { private: double open; // Open price double high; // High price double low; // Low price double close; // Close price public: //--- Default constructor CPrices(void); //--- Parametric constructor CPrices(double o,double h,double l, double c); };
Производные (дочерние) классы:
Как мы узнали ранее, концепция наследования является одной из наиболее ценных и полезных функций ООП, поскольку мы можем создать дочерний класс из суперкласса или родительского класса, и этот дочерний класс наследует все члены родительского класса, кроме приватных. После этого мы можем добавить новые переменные и функции для этого дочернего класса.
Приведем следующий пример: если у нас есть родительский класс для цен, мы можем создать дочерний класс для дневных цен, как показано ниже:
class CDailyPrices : public CPrices { public: double open; // Open price double high; // High price double low; // Low price double close; // Close price };
Как мы видим, имя родительского класса — CPrices, а CDailyPrices — дочерний, или производный класс. Все общедоступные и защищенные члены CPrices являются частью класса CDailyPrices и по-прежнему являются общедоступными.
Виртуальные функции:
Если мы хотим обновить способ работы метода или функции в дочернем классе, мы можем сделать это, используя (виртуальную) функцию в родительском классе, а затем определить функцию в дочернем классе. Например, если у нас есть две разные версии функции на основе класса. Для родительского класса мы определяем функцию, используя ключевое слово virtual
class CVar { public: virtual void varCal(); };
Затем мы обновляем ту же функцию в дочернем классе.
class CVar1 : public CVar { public: int varCal(int x, int y); };
Объекты:
Объекты имеют уникальный идентификатор. Как и при создании переменной, мы будем использовать имя класса в качестве типа перед идентификатором объекта. Мы можем создать множество объектов, принадлежащих нашим классам, так как для проекта нам нужно всего лишь использовать уникальный идентификатор для каждого. После объявления объекта мы можем получить доступ к любому публичному члену, используя (.) - точку.
Давайте рассмотрим пример, показывающий создание класса с целочисленной переменной количества сделок (num_trades),
class CSystrades { public: int num_trades; };
Затем нам нужно создать объект, принадлежащий этому классу, с именем system1. Мы сделаем это, выполнив следующие действия:
CSystrades system1;
Тогда мы можем определить этот объект по значению (3):
system1.num_trades=3;
Мы рассмотрели, как можно применить ООП в MQL5, изучив некоторые из наиболее важных моментов.
Примеры ООП
В этом интересном разделе мы представим несколько простых приложений, применяющих ООП.
priceClass:
В этом простом приложении нам нужно проверить цены на нескольких таймфреймах. Мы используем три таймфрейма (дневной, недельный и месячный). Нам также нужно увидеть все цены (открытие, максимум, минимум, закрытие) в одном месте, скажем, на вкладке "Эксперты". После этого мы можем продолжить разработку более сложных программ.
Во-первых, нам нужно объявить класс, выполнив следующие шаги:
- Нам нужно объявить класс для цен в глобальной области видимости и включить все общие члены как общедоступные, используя ключевое слово class.
- Использовать ключевое слово public.
- Создать пять переменных (timeframe, open, high, low и close).
- Создать функцию void для отображения всех данных о ценах.
class CPrices { public: string timeFrame; double open; double high; double low; double close; void pricesPrint() { Print(timeFrame," Prices = Open: ",open," - ","High: ",high,"-","Low: ",low,"-","Close: ",close); } };
Создадим объекты из класса для ежедневных, еженедельных и ежемесячных цен.
CPrices CDailyPrices; CPrices CWeeklyPrices; CPrices CMonthlyPrices;
Внутри функции OnInit определим следующее для трех таймфреймов:
- Таймфрейм строки.
- Цену открытия с помощью функции iOpen.
- Максимальную цену с помощью функции iHigh.
- Минимальную цену с помощью функции iLow.
- Цену закрытия с помощью функции iClose.
- Вызов функции или метода print.
int OnInit() { //--- Daily time frame CDailyPrices.timeFrame="Daily"; CDailyPrices.open=(iOpen(Symbol(),PERIOD_D1,1)); CDailyPrices.high=(iHigh(Symbol(),PERIOD_D1,1)); CDailyPrices.low=(iLow(Symbol(),PERIOD_D1,1)); CDailyPrices.close=(iClose(Symbol(),PERIOD_D1,1)); CDailyPrices.pricesPrint(); //--- Weekly time frame CWeeklyPrices.timeFrame="Weekly"; CWeeklyPrices.open=(iOpen(Symbol(),PERIOD_W1,1)); CWeeklyPrices.high=(iHigh(Symbol(),PERIOD_W1,1)); CWeeklyPrices.low=(iLow(Symbol(),PERIOD_W1,1)); CWeeklyPrices.close=(iClose(Symbol(),PERIOD_W1,1)); CWeeklyPrices.pricesPrint(); //--- Monthly time frame CMonthlyPrices.timeFrame="Monthly"; CMonthlyPrices.open=(iOpen(Symbol(),PERIOD_MN1,1)); CMonthlyPrices.high=(iHigh(Symbol(),PERIOD_MN1,1)); CMonthlyPrices.low=(iLow(Symbol(),PERIOD_MN1,1)); CMonthlyPrices.close=(iClose(Symbol(),PERIOD_MN1,1)); CMonthlyPrices.pricesPrint(); return(INIT_SUCCEEDED); }
После этого мы можем увидеть цены после работы советника на вкладке "Эксперты" панели инструментов:
Здесь мы видим три строки:
- В первой строке отображаются дневные цены открытия, максимума, минимума и закрытия.
- Во второй - те же цены по недельным данным.
- В третьей - по месячным.
indicatorClass:
Программа должна отображать значения четырех типов скользящих средних (простой, экспоненциальной, сглаженной и линейно-взвешенной), используя ООП. Ниже описаны простые шаги для достижения цели:
Объявим класс индикатора CiMA, используя ключевое слово class, и создадим общедоступные члены этого класса. Это четыре общие переменные: MAType - для определения типа скользящего среднего, MAArray - для определения массива скользящего среднего, MAHandle - для определения хендла каждого типа, MAValue - для определения значения каждой скользящей средней. Также создадим метод void или функцию valuePrint и тело функции для отображения значения каждого типа скользящего среднего.
class CiMA { public: string MAType; double MAArray[]; int MAHandle; double MAValue; void valuePrint() { Print(MAType," Current Value: ",MAValue); }; };
Создадим следующие объекты каждой скользящей средней из класса:
- Имя средней
- Хендл средней
- Массив средней
//--- SMA CiMA CSma; CiMA CSmaHandle; CiMA CSmaArray; //--- EMA CiMA CEma; CiMA CEmaHandle; CiMA CEmaArray; //--- SMMA CiMA CSmma; CiMA CSmmaHandle; CiMA CSmmaArray; //--- LWMA CiMA CLwma; CiMA CLwmaHandle; CiMA CLwmaArray;
Для каждого типа скользящей средней выполним следующие шаги внутри функции OnInit:
- Определим имя средней.
- Определим хендл средней.
- Установим флаг AS_SERIES для массива с помощью ArraySetAsSeries.
- Получим данные буфера средней с помощью функции CopyBuffer.
- Определите значение средней и нормализуем его с помощью функции NormalizeDouble.
- Вызовем созданный метод или функцию Print
int OnInit() { //--- SMA CSma.MAType="Simple MA"; CSmaHandle.MAHandle=iMA(_Symbol,PERIOD_CURRENT,10,0,MODE_SMA,PRICE_CLOSE); ArraySetAsSeries(CSmaArray.MAArray,true); CopyBuffer(CSmaHandle.MAHandle,0,0,3,CSmaArray.MAArray); CSma.MAValue=NormalizeDouble(CSmaArray.MAArray[1],_Digits); CSma.valuePrint(); //--- EMA CEma.MAType="Exponential MA"; CEmaHandle.MAHandle=iMA(_Symbol,PERIOD_CURRENT,10,0,MODE_EMA,PRICE_CLOSE); ArraySetAsSeries(CEmaArray.MAArray,true); CopyBuffer(CEmaHandle.MAHandle,0,0,3,CEmaArray.MAArray); CEma.MAValue=NormalizeDouble(CEmaArray.MAArray[1],_Digits); CEma.valuePrint(); //--- SMMA CSmma.MAType="Smoothed MA"; CSmmaHandle.MAHandle=iMA(_Symbol,PERIOD_CURRENT,10,0,MODE_SMMA,PRICE_CLOSE); ArraySetAsSeries(CSmmaArray.MAArray,true); CopyBuffer(CSmmaHandle.MAHandle,0,0,3,CSmmaArray.MAArray); CSmma.MAValue=NormalizeDouble(CSmmaArray.MAArray[1],_Digits); CSmma.valuePrint(); //--- LWMA CLwma.MAType="Linear-weighted MA"; CLwmaHandle.MAHandle=iMA(_Symbol,PERIOD_CURRENT,10,0,MODE_LWMA,PRICE_CLOSE); ArraySetAsSeries(CLwmaArray.MAArray,true); CopyBuffer(CLwmaHandle.MAHandle,0,0,3,CLwmaArray.MAArray); CLwma.MAValue=NormalizeDouble(CLwmaArray.MAArray[1],_Digits); CLwma.valuePrint(); return(INIT_SUCCEEDED); }
После компиляции и выполнения кода мы увидим четыре строки для каждого типа скользящей средней. Каждая строка отображает значение средней:
Как я уже говорил, эти приложения можно усовершенствовать, чтобы они выполняли более сложные задачи. Однако наша задача в этой статье - изучить основы ООП и освоить их применение на практике.
Заключение
В этой статье мы изучили основы очень важного подхода в программировании. Объектно-ориентированное программирование помогает в создании безопасного программного обеспечения, упрощает разработку за счет разделения кода на небольшие блоки, позволяет создавать множество экземпляров одного и того же класса без каких-либо конфликтов, даже если они ведут себя по-разному, обеспечивая большую гибкость и безопасность при обновлении.
Мы также узнали, как применять этот важный подход в MQL5, чтобы получить все эти невероятные возможности, а затем изучили несколько простых приложений, которые можно создать, применив ООП в MQL5.
Надеюсь, статья была полезна.
Если вы хотите узнать больше о создании в MQL5 торговых систем на основе наиболее популярных индикаторов, а также о разработке и применении пользовательских индикаторов в составе советников, вы можете ознакомиться с другими моими статьями. Вы можете найти полный список статей в моем профиле.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/12813
- Бесплатные приложения для трейдинга
- Форексный VPS бесплатно на 24 часа
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Надо же, как время летит )). Лет 10 назад я на этом форуме пытался пару раз открыть ветку по ООП в русскоязычной и англо части. В русской завалили истериками, что и так все сложно и нам, пролетариям, не надоть! Деды пахали сохой и мы не нарушим традиций! В англо просто убили ветку без объяснения причин.
А теперь нас Мухамеды учат )). Статья перепечатка с какого-то занудного академического учебника, я уснул на первом абзаце.
Надо же, как время летит )). Лет 10 назад я на этом форуме пытался пару раз открыть ветку по ООП в русскоязычной и англо части. В русской завалили истериками, что и так все сложно и нам, пролетариям, не надоть! Деды пахали сохой и мы не нарушим традиций! В англо просто убили ветку без объяснения причин.
А теперь нас Мухамеды учат )). Статья перепечатка с какого-то занудного академического учебника, я уснул на первом абзаце.
Наверное это было слишком рано. Тогда ещё мало кто использовал ООП в своей работе. А кто знал и использовал, тот не желал тратить время а обсуждение.
В отличии от тебя Алексей, я не уснул, дочитал до конца, но с середины статьи начал пропускать по несколько строк… В общем статья мне не понравилась. Ничего того, чего нет в документации я тут не вижу.
Начнем с определения ООП. ООП помогает создавать и разрабатывать повторно используемое программное обеспечение без дублирования работы и кода с применением концепции DRY (не повторяйся).
В этом что то есть, а где определение ООП?
Инкапсуляция это инкапсуляция которая позволяет... Заходило трудно, понятие видимость для ООПшников видимо приватно)))) И то что модификатор доступа это и есть инкапсуляция, об этом читатели сами должны догадаться))))
Да нормальный бизнес, за 200 тугриков выжимку из учебника делать, надеюсь хоть сам писал, без ГПТ))))