ООП vs процедурное программирование - страница 33

 
Andrei:

За то на MQL4 нельзя программировать с ООП, поэтому он все еще популярней.

Я уже показывал свой код, и покажу еще раз:

class CTradeProcessorI : public CMyObject
{
public:
   void CTradeProcessorI() {    SetMyObjectType(MOT_TRADE_PROCESSOR_I); };
   virtual void ~CTradeProcessorI() {};
   
   // Настроечный интерфейс
   virtual void SetSlippage(uint uiSlippage) = 0;
   
   // Торговый интерфейс
   // Все функции возвращают код возврата торгового сервера
   virtual int Buy(long & lTicket,ECurrencySymbol csSymbol,double dVolume,double dTP=0,double dSL=0,ulong ulMagic = 0,string strComment = NULL) = 0;               // Всегда по цене Ask, если успешно - возвращается lTicket
   virtual int Sell(long & lTicket,ECurrencySymbol csSymbol,double dVolume,double dTP=0,double dSL=0,ulong ulMagic = 0,string strComment = NULL) = 0;              // Всегда по цене Bid, если успешно - возвращается lTicket  

   virtual int ModifyTPSL(CTradePosComponentI* ptpcComponent,double dTP=0,double dSL=0) = 0;       
   virtual int ModifyTPSL(long lTPCTicket,double dTP=0,double dSL=0) = 0;       

   virtual int CloseTradeComponent(CTradePosComponentI* ptpcComponent,double dCloseVolume=EMPTY_VALUE) = 0;              // dCloseVolume - закрываемый объем. Если равен EMPTY_VALUE или равен или больше, чем объем торговой компоненты с указанным тикетом - закрывается вся торговая компонента.   
   virtual int CloseTradeComponent(long lTPCTicket,double dCloseVolume=EMPTY_VALUE) = 0;              // dCloseVolume - закрываемый объем. Если равен EMPTY_VALUE или равен или больше, чем объем торговой компоненты с указанным тикетом - закрывается вся торговая компонента.   
   
   virtual int PendingSet(long & lTicket,ECurrencySymbol csSymbol,ENUM_ORDER_TYPE otOrderType,double dSetPrice,double dVolume,double dTP=0,double dSL=0,ulong ulMagic = 0,string strComment = NULL) = 0; // если успешно - возвращается lTicket
   virtual int PendingDelete(long lTicket) = 0; 
   virtual int PendingDelete(COrderInfoCore* poiOrder) = 0; 
   
   virtual int PendingModify(long lTicket,double dSetPrice,double dTP=0,double dSL=0) = 0;       
   virtual int PendingModify(COrderInfoCore* poiOrder,double dSetPrice,double dTP=0,double dSL=0) = 0;       
   
   // Проверка кода возврата
   virtual bool TradeOperationWasSuccessful(int iTradeResCode) = 0;
   
   // Если функция возвращает true, то при возникновении пользовательских ошибок (iTradeResCode > ERR_USER_ERROR_FIRST) советник прекратит работу
   // В случае false - работа будет продолжена
   virtual bool IsUserErrorsFalal() = 0;
};


Это интерфейс торгового процессора - он совершенно одинаков, как для МТ4, так и для МТ5.

Пользователь просто получает этот интерфейс - и у него все возможности для торговых действий. Ему совершенно не надо даже знать, где он находится - на МТ4 или МТ5. Нужно совершить покупку - вызываете функцияю Buy. которая вам заполнит тикет открытой торговой компоненты (для МТ4 - это ордер, для МТ5 - позиция), и вернет код возврата торгового сервера.

Вам даже не надо задумываться над разностью протоколов МТ4 и МТ5 - интерфейс предоставляет всё необходимое.  

Все это - возможности ООП.

 
George Merts:

Я уже показывал свой код, и покажу еще раз:

Это интерфейс торгового процессора - он совершенно одинаков, как для МТ4, так и для МТ5.

Пользователь просто получает этот интерфейс - и у него все возможности для торговых действий. Ему совершенно не надо даже знать, где он находится - на МТ4 или МТ5.

И все это - благодаря ООП.

А примеры использования есть для типичных случаев?

 
Andrei:
Если бы было по вашей теории, что MQL4=MQL5, то тогда MQL4 можно было запускать на МТ5 и наоборот.
Мой код совершенно без изменений запускается на МТ4 и на МТ5.
 
Andrei:

А примеры использования есть для типичных случаев?

Ну, допустим, вот моя функция, отправляющая запрос изменения ТП-СЛ на торговый процессор:

EEAWorkRetcode CChngTPSLRequest::_ProceedRequestInto(CTradeProcessorI* ptpProcessor)
{
   ASSERT_MYPOINTER(ptpProcessor);
   
   m_uiServerRetCode = ptpProcessor.ModifyTPSL(m_lComponentTicket,m_dTP,m_dSL);

   if(ptpProcessor.TradeOperationWasSuccessful(m_uiServerRetCode) != true)
      {
      Print("Торговый запрос на изменение ТП-СЛ компоненты отработал с ошибкой, код возврата: ",m_uiServerRetCode);
      TRACE_INTEGER("Торговый запрос на изменение ТП-СЛ компоненты отработал с ошибкой, код возврата: ",m_uiServerRetCode);
      return(WR_SERVER_PROCEED_ERROR);
      };
   
   return(WR_SUCCEEDED);   
};

Сперва объекты-части эксперта - формируют запросы на торговые действия (вот, один из таких запросов - на изменение ТП-СЛ). После этого у всех запросов вызывается функция ProceedRequestInto() чтобы отправить информацию о торговом действии в торговый процессор.

Сам торговый процессор представляет из себя объект следующего класса:

// СTradeProcessor - переносимый класс торгового процессора
// Именно этот класс необходимо использовать для торговли. 
// Класс реализует интерфейс CTradeProcessorI

#ifdef __MQL5__
#include <MyLib\Trade\MT5TradeProcessor.mq5>
#else // __MQL5__
#include <MyLib\Trade\MT4TradeProcessor.mq5>
#endif //__MQL5__

#ifdef __MQL5__
class CTradeProcessor : public CMT5TradeProcessor
#else // __MQL5__
class CTradeProcessor : public CMT4TradeProcessor
#endif //__MQL5__

{
public:
   void CTradeProcessor(uint uiSlippage = DEFAULT_TRADE_POINT_SLIPPAGE);
   void ~CTradeProcessor() {};
 
   // Функции отложенных ордеров, которые используют платформоспецифические  
   virtual int PendingDelete(COrderInfoCore* poiOrder);
   virtual int PendingModify(COrderInfoCore* poiOrder,double dSetPrice,double dTP=0,double dSL=0);          
};

То есть, в зависимости от платформы - класс CTradeProcessor наследуется либо от класса CMT5TradeProcessor, либо от класса CMT4TradeProceccor.

Все это, конечно, можно сделать и без ООП - с помощью переключателей да ifdef'ов. Но, на мой взгляд, ООП-подход - куда более удобный и ясный. А главное - позволяющий изолировать сущности друг от друга, и избавляться от массы глобальных переменных.

Кстати, еще один "отголосок ООП" - как раз в дополнительных функциях работы с отложками. Торговый процессор - работает с тикетами отложек, что неудобно - обращение к тикетам в МТ4 и МТ5 разное. Поэтому есть общий класс COrderInfoCore - наследник интерфейса ордера. В процессор гораздо удобнее передавать просто указатель на этот объект. Соответственно, таки образом - мы обходим платформозависиые места.

 
George Merts:

Ну, допустим, вот моя функция, отправляющая запрос изменения ТП-СЛ на торговый процессор:

Сперва объекты-части эксперта - формируют запросы на торговые действия (вот, один из таких запросов - на изменение ТП-СЛ). После этого у всех запросов вызывается функция ProceedRequestInto() чтобы отправить информацию о торговом действии в торговый процессор.

Мне кажется слишком замудрено, чтобы понять что там делается внутри на самом деле... А без понимания сути работы наврядли кто-то воспользуется... Не проще ли написать отдельную версию для МТ5 и подцеплять ее когда надо?
 
George Merts:
Мой код совершенно без изменений запускается на МТ4 и на МТ5.

А зачем запускать в разных терминалах?

 
Andrei:
Мне кажется слишком замудрено, чтобы понять что там делается внутри на самом деле... А без понимания сути работы наврядли кто-то воспользуется... Не проще ли написать отдельную версию для МТ5 и подцеплять ее когда надо?
А зачем "понимать, что там делается внутри на самом деле" ? Есть фиксированный интерфейс, который выполняет действие, независимо от платформы - его и используем. А что там, на низком уровне - какая разница ?
 

George Merts:

Но, на мой взгляд, ООП-подход - куда более удобный и ясный. А главное - позволяющий изолировать сущности друг от друга, и избавляться от массы глобальных переменных.

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

 
СанСаныч Фоменко:

А зачем запускать в разных терминалах?

А затем, что у меня основной счет открыт на МТ4, а тестер стратегий на МТ5 куда лучше.

Да и во Фрилансе, по слухам, очень частое требование заказчиков - "чтобы работало и на МТ4 и на МТ5" - значит, это неспроста. Сам я во Фрилансе не вижу смысла работать, но можно спросить у тех, кто там работает, зачем заказчики требуют кроссплатформенность.

 
George Merts:
А зачем "понимать, что там делается внутри на самом деле" ? Есть фиксированный интерфейс, который выполняет действие, независимо от платформы - его и используем. А что там, на низком уровне - какая разница ?
Не идет речь о низком уровне, а о логике того что там куда перетекает и во что превращается в каждый возможный момент времени, включая знание всех внутренних переменных... Без понимания всей этой избыточной логики смысл использования данного кода для не автора пропадает начисто...