OOP vs. prozedurale Programmierung - Seite 33

 
Andrei:

Aber man kann in MQL4 nicht mit OOP programmieren, deshalb ist es immer noch beliebter.

Ich habe meinen Code bereits gezeigt, und ich werde ihn noch einmal zeigen:

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;
};


Dies ist die Schnittstelle des Handelsprozessors - sie ist für MT4 und MT5 identisch.

Der Benutzer erhält nur diese Schnittstelle - und hat alle Möglichkeiten für Handelsaktionen. Sie müssen nicht einmal wissen, ob es sich um MT4 oder MT5 handelt. Sie müssen kaufen - rufen Sie die Funktion Buy auf, die das Ticket für die offene Handelskomponente füllt (für MT4 ist es eine Order, für MT5 eine Position) und den Rückgabecode an den Handelsserver zurückgibt.

Sie müssen nicht einmal über den Unterschied zwischen MT4- und MT5-Protokollen nachdenken - die Schnittstelle bietet alles, was Sie brauchen.

Dies alles sind OOP-Fähigkeiten.

 
George Merts:

Ich habe meinen Code bereits gezeigt, und ich werde ihn noch einmal zeigen:

Dies ist die Schnittstelle des Handelsprozessors - sie ist für MT4 und MT5 identisch.

Der Nutzer erhält einfach diese Schnittstelle - und schon hat er alle Möglichkeiten für Handelsaktionen. Er muss nicht einmal wissen, ob er mit MT4 oder MT5 arbeitet.

Und das ist alles OOP zu verdanken.

Gibt es Anwendungsbeispiele für typische Fälle?

 
Andrei:
Wenn Ihre Theorie war, dass MQL4=MQL5, dann MQL4 könnte auf MT5 und umgekehrt ausgeführt werden.
Mein Code läuft völlig unverändert auf MT4 und MT5.
 
Andrei:

Haben Sie Beispiele für die Verwendung in typischen Fällen?

Nun, nehmen wir an, meine Funktion sendet einen Antrag auf Änderung von TP-SL an den Handelsprozessor:

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);   
};

Erstens, EA part objects - form trade action requests (hier ist eine solche Anfrage, TP-SL zu ändern). Danach wird die Funktion ProceedRequestInto() für alle Anfragen aufgerufen, um Informationen über eine Handelsaktion an den Handelsverarbeiter zu senden.

Der Handelsabwickler selbst ist ein Objekt der folgenden Klasse:

// С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);          
};

Das heißt, je nach Plattform wird die Klasse CTradeProcessor entweder von der Klasse CMT5TradeProcessor oder von der Klasse CMT4TradeProceccor geerbt.

Natürlich könnte all dies auch ohne OOP, mit Hilfe von Schaltern und ifdefs geschehen. Aber meiner Meinung nach ist der OOP-Ansatz bequemer und klarer, und das Wichtigste ist, dass er es erlaubt, Entitäten voneinander zu isolieren und die Masse an globalen Variablen loszuwerden.

Ein weiteres "Echo von OOP" findet sich übrigens in den zusätzlichen Funktionen für die Arbeit mit den ausstehenden Aufträgen. Der Handelsprozessor - arbeitet mit Tickets von Geschäften, was unpraktisch ist - der Bezug auf das Ticket in MT4 und MT5 ist unterschiedlich. Aus diesem Grund gibt es die gemeinsame Klasse COrderInfoCore, die von der Auftragsschnittstelle abstammt. Es ist viel bequemer, dem Prozessor nur einen Zeiger auf dieses Objekt zu übergeben. Auf diese Weise umgehen wir die plattformabhängigen Fragmente.

 
George Merts:

Nun, nehmen wir an, meine Funktion sendet einen Antrag auf Änderung von TP-SL an den Handelsprozessor:

Erstens, EA part objects - form trade action requests (hier ist eine solche Anfrage, TP-SL zu ändern). Dann wird die Funktion ProceedRequestInto() für alle Anfragen aufgerufen, um Informationen über eine Handelsaktion an einen Handelsverarbeiter zu senden.

Es scheint mir zu kompliziert zu sein, um zu verstehen, was da eigentlich passiert. Und wenn Sie nicht verstehen, was darin vor sich geht, werden Sie es wahrscheinlich auch nicht benutzen... Wäre es nicht einfacher, eine separate Version für MT5 zu schreiben und diese bei Bedarf einzubinden?
 
George Merts:
Mein Code läuft völlig unverändert auf MT4 und MT5.

Warum in verschiedenen Terminals laufen?

 
Andrei:
Ich denke, es ist zu kompliziert, um zu verstehen, was da wirklich vor sich geht... Und ohne zu verstehen, wie es funktioniert, wird es wohl niemand nutzen... Ist es nicht einfacher, eine separate Version für MT5 zu schreiben und diese bei Bedarf einzubinden?
Warum muss ich "verstehen, was wirklich drin ist"? Es gibt eine feste Schnittstelle, die eine Aktion ausführt, unabhängig von der Plattform - das ist es, was wir verwenden. Und was gibt es, auf niedrigem Niveau - was macht das für einen Unterschied?
 

George Merts:

Meiner Meinung nach ist der OOP-Ansatz jedoch viel praktischer und übersichtlicher, und - was am wichtigsten ist - er erlaubt es, Entitäten voneinander zu isolieren und die Massen an globalen Variablen loszuwerden.

Das ist der Punkt, wenn man alles von allem isoliert hat, wird es viel schwieriger sein, mit solchem Code umzugehen, ganz zu schweigen von der Unmöglichkeit, den Code angemessen zu debuggen, wenn man die aktuellen Werte aller erforderlichen Variablen kennen muss...

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

Warum in verschiedenen Terminals laufen?

Denn mein Hauptkonto ist auf MT4 eröffnet, und mein Strategietester ist viel besser auf MT5.

Es ist eine häufige Forderung der Kunden in Freelance - "es muss sowohl auf MT4 als auch auf MT5 funktionieren" - das bedeutet, dass es einen Grund dafür gibt. Ich selbst sehe keinen Grund, in der Freiberuflichkeit zu arbeiten, aber Sie können diejenigen, die dort arbeiten, fragen, warum Kunden plattformübergreifend arbeiten wollen.

 
George Merts:
Warum müssen wir "verstehen, was da drinnen eigentlich gemacht wird"? Es gibt eine feste Schnittstelle, die eine Aktion ausführt, unabhängig von der Plattform - das ist es, was wir verwenden. Und was gibt es, auf niedrigem Niveau - was macht das für einen Unterschied?
Es geht nicht um die niedrige Ebene, sondern um die Logik dessen, was zu jedem möglichen Zeitpunkt wohin und in was fließt, einschließlich der Kenntnis aller internen Variablen... Wenn man diese ganze redundante Logik nicht versteht, geht der Sinn der Verwendung dieses Codes für einen Nicht-Autor völlig verloren...