English Русский 中文 Español 日本語 Português
preview
Entwurfsmuster in der Softwareentwicklung und MQL5 (Teil I): Erzeugungsmuster

Entwurfsmuster in der Softwareentwicklung und MQL5 (Teil I): Erzeugungsmuster

MetaTrader 5Handel | 13 Februar 2024, 16:03
170 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Einführung

Im Bereich der Programmierung haben wir ein wichtiges Ziel, nämlich die Lösung von Problemen, aber wir können das gleiche Problem in verschiedenen Bereichen in der gleichen oder einer anderen Software haben. Stellen wir uns vor, dass wir jedes Mal, wenn wir mit dieser Art von Problem konfrontiert werden, dieselben Schritte unternehmen und dieselbe Zeit aufwenden, um es zu lösen - das bedeutet, dass wir das Rad immer wieder neu erfinden. Es besteht kein Zweifel, dass dies ein nutzloser Ansatz ist, da er viel Zeit und Mühe kostet. Daher ist die folgende Frage in diesem Fall entscheidend: Gibt es eine Methode, die wir anwenden können, um diese ineffiziente Zeit und Mühe zu sparen?

Die Antwort lautet: Ja, es gibt Methoden oder, sagen wir, Muster, die wir zur Lösung bestimmter Probleme verwenden können, und das sind Entwurfsmuster. Entwurfsmuster sind sehr hilfreich bei der Anwendung des DRY-Konzepts (Do not Repeat Yourself), was bedeutet, dass wir vermeiden können, das Rad neu zu erfinden. Wenn wir ein Problem haben und ein Muster haben, mit dem wir es effektiv lösen können, dann werden wir dieses Muster verwenden, um es zu lösen und Zeit und Mühe zu sparen.

Das Thema Entwurfsmuster (Design Pattern) besteht darin, dass wir einen seiner Typen auf der Grundlage seines Zwecks teilen und versuchen werden, einen praktischen Leitfaden darüber bereitzustellen, wie wir sie beim Entwurf unserer Software mit MQL5 verwenden können.

Wir werden die folgenden Themen behandeln:

Entwurfsmuster sind, wie wir sehen werden, ein sehr wichtiges Thema, das man lernen und anwenden muss, wenn man seine Leistung und Produktivität als Softwareentwickler steigern will. Wir werden versuchen, die Konzepte dieses interessanten und wichtigen Themas so weit wie möglich zu vereinfachen, damit sie auch für Anfänger gut verständlich sind. Wir werden auch einfache Beispiele dafür geben, wie wir diese Muster in MQL5 verwenden können, um zu versuchen, einen praktischen Leitfaden für jeden zu bieten, der dieses wichtige Thema im Allgemeinen lernen muss.

Wir werden versuchen, jede Art dieser Muster zusammenzufassen und so viel wie möglich auf den Punkt zu bringen, ohne zu ignorieren, was das Verständnis erschweren kann, wenn es fehlt. Ich hoffe, dass Sie diesen Artikel aufschlussreich finden und eine neue Sache in der Welt der Programmierung lernen, wenn Sie neu in diesem Bereich sind.

Es ist auch wichtig zu erwähnen, dass Sie unbedingt Kenntnisse über das objektorientierte Thema haben müssen, um zu verstehen, was Sie in diesem Artikel lesen werden. Wenn Sie etwas über objektorientierte Programmierung (OOP) lernen wollen, können Sie den Artikel MQL5 objektorientierte Programmierung (OOP) verstehen lesen.

Haftungsausschluss: Alle Informationen werden in der vorliegenden Form nur zu Informationszwecken bereitgestellt und sind nicht für Handelszwecke oder als Ratschläge gedacht. Die Informationen garantieren keinen Erfolg. Wenn Sie sich dafür entscheiden, diese Materialien auf einem Ihrer Handelskonten zu verwenden, tun Sie dies auf eigenes Risiko und Sie sind allein verantwortlich.


Definition von Entwurfsmuster

In diesem Teil werden wir Entwurfsmuster identifizieren. Sie sind einfach diejenigen Muster, die als Lösungen für spezifische, beschriebene und wiederkehrende Probleme in der Softwareentwicklung verwendet werden können. Jedes Entwurfsmuster konzentriert sich auf ein bestimmtes objektorientiertes Problem. Diese Muster können leicht in gängigen objektorientierten Programmiersprachen wie C++ implementiert werden. Wenn wir über ein Entwurfsmuster sprechen, können wir sagen, dass es die vier wichtige Elemente für dieses Muster gibt:

  • Der Mustername (pattern name): bezieht sich auf den Namen des Musters, das zur Lösung eines spezifischen und beschriebenen Problems verwendet werden kann.
  • Das Problem (problem): bezieht sich auf das beschriebene, wiederholte und spezifische Problem, mit dem wir konfrontiert werden können.
  • Die Lösung (solution): bezieht sich auf die beschriebene Lösung für ein bestimmtes beschriebenes Problem.
  • Die Konsequenzen (consequences): beziehen sich auf die Ergebnisse nach Anwendung des Musters zur Lösung des Problems.

Es gibt drei Hauptkategorien von Entwurfsmustern, die auf dem folgenden Zweck basieren:

  • Erzeugungsmuster (Creational patterns): sie helfen bei der Schaffung eines unabhängigen Systems, indem sie Objekte erstellen, zusammensetzen und darstellen.
  • Strukturelle Muster (Structural patterns): Verwendung der erstellten Objekte zur Bildung größerer Strukturen.
  • Verhaltensmuster (Behavioral patterns): verantwortlich für die Kommunikation zwischen Objekten.

Erzeugungsmuster

In diesem Teil werden wir Informationen über die Erzeugungsmuster (Creational patterns) präsentieren und wie sie bei der Erstellung unserer Software helfen können. Wie bereits erwähnt, hilft diese Art von Entwurfsmuster dabei, ein unabhängiges System durch das Erstellen, Zusammenstellen und Darstellen von Objekten zu schaffen. Diese Muster tragen nicht nur dazu bei, Fragen oder Probleme effizient zu lösen, sondern helfen auch dabei, Ihre Software auf effektive Weise zu konstruieren, um sicherzustellen, dass Ihre Software wiederverwendbar, erweiterbar und gut und einfach getestet ist, indem sie helfen, sauberen Code zu schreiben.

Klassen des Erzeugungsmusters verwenden das Vererbungskonzept, um die Klasse als Instanz zu variieren, während das Objekt des Erzeugungsmusters die Aufgabe der Instanziierung an ein anderes Objekt abgibt. Wenn sich die Software mehr auf die Objektkomposition als auf die Klassenvererbung konzentriert, gewinnen die Erzeugungsmuster an Bedeutung.

Wir können sagen, dass die Erzeugungsmuster zwei wiederkehrende Themen haben:

  • Sie verwenden das Konzept der Kapselung, um das Wissen über die konkreten Klassen, die vom System verwendet werden können.
  • Sie machen die Methode zur Erstellung von Instanzen von Klassen und deren Zusammenstellung unsichtbar.

Erzeugungsmuster helfen dabei, flexibel zu entscheiden, was, wer und wie etwas geschaffen werden kann, und wann es geschaffen wird.

Sie tragen auch zur Abstraktion des Instanziierungsprozesses bei, da sie es uns ermöglichen, Objekte zu erstellen, ohne dieselbe Implementierung zu wiederholen, und das trägt dazu bei, unseren Code flexibler und einfacher zu gestalten.

In diesem Artikel werden wir die Erzeugungsmuster den folgenden Mustern gleichstellen:

  • Abstrakte Fabrik (Abstract Factory): Sie bietet uns eine Schnittstelle zur Erstellung von Objektfamilien, ohne deren Klassen zu erwähnen.
  • Erbauer (Builder): Er hilft bei der Erstellung komplexer Objekte und trennt die Konstruktion des Objekts von seiner Darstellung, wodurch verschiedene Darstellungen desselben Objekts mit demselben Konstruktionsprozess erstellt werden können.
  • Fabrikmethode (Factory Method): Sie hilft bei der Definition der Schnittstelle für die Erstellung von Objekten und ermöglicht es ihren Unterklassen zu entscheiden, welche Klasse instanziiert werden soll.
  • Prototyp (Prototype): Er hilft bei der Festlegung der zu erstellenden Objekttypen, indem er eine prototypische Instanz verwendet und dann diesen Prototyp kopiert, um neue Objekte zu erstellen.
  • Singleton (Singleton): Es hilft sicherzustellen, dass die Klasse nur eine Instanz hat und einen globalen Zugangspunkt bietet.

Wir werden die vorherigen Muster im Detail kennen lernen und erfahren, wie wir sie in der MQL5-Software durch den folgenden Ansatz anwenden und nutzen können:

  • Was bewirkt das Muster?
  • Welches Designproblem wird damit gelöst?
  • Wie können wir es in MQL5 verwenden?


Abstrakte Fabrik

In diesem Teil werden wir einen Blick auf eines der Erzeugungsmuster werfen, nämlich die Abstrakte Fabrik. Wie wir im Muster Abstract Factory sehen werden, sind Fabriken und Produkte die Hauptakteure in diesem Muster, und es kann dazu verwendet werden, uns bei der Erstellung von Familien verwandter Produktobjekte ohne direkte Instanziierung von Klassen zu helfen. Sie kann verwendet werden, wenn die Anzahl und die allgemeinen Arten von Produktobjekten konstant sind, sie sich aber in bestimmten Produktfamilien unterscheiden.

Was bewirkt das Muster?

Dieses Muster bietet eine Schnittstelle zur Erstellung von Objektfamilien ohne Angabe der Klassen, und diese erstellten Objekte können verwandt oder unabhängig sein. Es ist auch als Kit bekannt. Im Folgenden finden Sie ein Diagramm, das die Funktionsweise und die Aufgaben dieses Musters erklärt.

Abstract Factory

Wie wir im vorherigen Diagramm sehen können, ist es bei vielen ähnlichen Produkten, die von vielen verschiedenen Herstellern oder Fabriken produziert werden, wie im vorherigen Beispiel, schwierig, zukünftige Änderungen vorzunehmen, wenn wir nicht das Muster der Abstrakten Fabrik verwenden. Mit Hilfe dieses Musters können wir das einfach und problemlos erreichen.

In diesem Muster definieren wir eine Klasse der Abstrakte Fabrik, die die Schnittstelle für Operationen zur Erstellung abstrakter Produkte deklariert. Wir haben auch eine abstrakte Klasse für jede Fabrik mit Unterklassen für zwei Produkte, und jede Fabrik wird ihre Produkte zurückgeben, je nachdem, welches Produkt vom Kunden aufgerufen wird.

Welches Designproblem wird damit gelöst?

Wir können dieses Muster also in den folgenden Fällen verwenden:

  • Wir brauchen ein unabhängiges System.
  • Wir brauchen ein konfiguriertes System mit einer von vielen Produktfamilien.
  • Wir müssen eine Familie von verwandten Produktobjekten gemäß ihrem Design zusammen verwenden und diese Einschränkung durchsetzen.
  • Wir müssen nur die Schnittstellen der bereitgestellten Klasse offenlegen, nicht ihre Implementierung.

Wir können also sagen, dass die Anwendung dieses Musters nur anhand der folgenden Beispiele von Vorteil sein kann:

  • Es hilft bei der Ausführung der Isolierung konkreter Klassen, weil es bei der Kontrolle der erstellten Objektklassen hilft. Dies kann durch die Kapselung der Verantwortung und des Prozesses zur Erstellung von Objekten, die Isolierung des Clients von den Implementierungsklassen, die Manipulation von Instanzen durch die abstrakten Schnittstellen der Clients und die Isolierung der Klassennamen des Produkts innerhalb der Implementierung der konkreten Fabrik erreicht werden, sodass sie nicht im Client-Code erscheinen.
  • Es erleichtert den Wechsel zwischen den Produktfamilien.

Wie können wir es in MQL5 verwenden?

In diesem Teil werden wir sehen, wie wir die Struktur der Abstrakten Fabrik in der Include-Datei kodieren können, aber es ist gut zu erwähnen, dass wir hier die Struktur kodieren, aber Sie können kodieren, was basierend auf dem Handelsfeld geeignet ist.

Im Folgenden wird die Struktur in den folgenden Schritten kodiert:

Mit dem Schlüsselwort Namespace deklarieren wir die Funktion AbstractFactory, um alle Funktionen aufzulisten, die wir innerhalb von

namespace AbstractFactory

Mit dem Schlüsselwort Interface wird die Funktion AbstractProductA deklariert

interface AbstractProductA
  {
  };

Mit dem Schlüsselwort interface deklarieren wir die Funktion AbstractProductB mit einer void Interact-Variable im Körper der Funktion

interface AbstractProductB
  {
   void Interact(AbstractProductA*);
  };

Deklaration einer Schnittstelle für Operationen zur Erstellung abstrakter Produkte

interface AbstractFactory
  {
   AbstractProductA* CreateProductA(void);
   AbstractProductB* CreateProductB(void);
  };

Konstruktion der Produkte A1 und A2 durch Definition des Produktobjekts, das wir durch die konkrete Fabrik und ihre Implementierungen über die abstrakte Produktschnittstelle erstellen müssen:

class ProductA1:public AbstractProductA
  {
public:
                     ProductA1(void);
  };
void ProductA1::ProductA1(void) 
{
Print("Product A1 is constructed");
}
class ProductA2:public AbstractProductA
  {
public:
                     ProductA2(void);
  };
void ProductA2::ProductA2(void) 
{
Print("Product A2 is constructed");
}

Konstruktion der konkreten Produkte B1 und B2 und anschließende Interaktion mit dem abstrakten Produkt A:

class ProductB1:public AbstractProductB
  {
public:
                     ProductB1(void);
   void              Interact(AbstractProductA*);
  };
void ProductB1::ProductB1(void) 
{
Print("Product B1 is constructed");
}
void ProductB1::Interact(AbstractProductA*src)
  {
   Print("Product B1: ",&this," is interacting with Product A: ",src);
  }
class ProductB2:public AbstractProductB
  {
public:
                     ProductB2(void);
   void              Interact(AbstractProductA*);
  };
void ProductB2::ProductB2(void) 
{
Print("Product B2 is constructed");
}
void ProductB2::Interact(AbstractProductA*src)
  {
   Print("Product B2: ",&this," is interacting with Product A: ",src);
  }

Erklärung der konkreten Fabriken Fabrik 1 und 2 zur Erzeugung und Rückgabe der Produkte A1, A2, B1, B2

class Factory1:public AbstractFactory
  {
public:
                     Factory1(void);
   AbstractProductA* CreateProductA(void);
   AbstractProductB* CreateProductB(void);
  };
void Factory1::Factory1(void)
  {
   Print("Factory 1: ",&this," is constructed");
  }
AbstractProductA* Factory1::CreateProductA(void)
  {
   Print("Factory 1 creates and returns Product A1");
   return new ProductA1;
  }
AbstractProductB* Factory1::CreateProductB(void)
  {
   Print("Factory 1 creates and returns Product B1");
   return new ProductB1;
  }
class Factory2:public AbstractFactory
  {
public:
                     Factory2(void);
   AbstractProductA* CreateProductA(void);
   AbstractProductB* CreateProductB(void);
  };
void Factory2::Factory2(void)
  {
   Print("Factory 2: ",&this," is constructed");
  }
AbstractProductA* Factory2::CreateProductA(void)
  {
   Print("Factory 2 creates and returns Product A2");
   return new ProductA2;
  }
AbstractProductB* Factory2::CreateProductB(void)
  {
   Print("Factory 2 creates and returns Product B2");
   return new ProductB2;
  }

Deklaration der Klasse FactoryClient und Verwendung von Schnittstellen, die von der Abstrakten Fabrik und dem abstrakten Produkt deklariert werden.

class FactoryClient
  {
public:
   void              Run(void);
   void              Switch(AbstractFactory*);
                     FactoryClient(AbstractFactory*);
                    ~FactoryClient(void);
protected:
   AbstractProductA* apa;
   AbstractProductB* apb;
   AbstractFactory*  factory;
   void              Delete(void);
  };
void FactoryClient::FactoryClient(AbstractFactory* af)
  {
   Print("Factory client created and received Abstract Factory ",af);
   Print("Factory client requests to accept/switch the factories");
   Switch(af);
  }
void FactoryClient::~FactoryClient(void)
  {
   Delete();
  }
void FactoryClient::Run(void)
  {
   Print("Factory client runs the abstract Product B");
   apb.Interact(apa);
  }
void FactoryClient::Delete(void)
  {
   delete apa;
   delete apb;
   delete factory;
  }
void FactoryClient::Switch(AbstractFactory *af)
  {
   string sFactory;
   StringConcatenate(sFactory,sFactory,factory);
   int iFactory=(int)StringToInteger(sFactory);
   if(iFactory>0)
     {
      Print("Factory client switches the old factory ",factory," to the new one ",af);
     }
   else
     {
      Print("Factory client accepts the new factory ",af);
     }
   Delete();
   factory=af;
   Print("Factory client saved the new factory");
   Print("Factory client requests its new factory to create the Product A");
   apa=factory.CreateProductA();
   Print("Factory client requests its new factory to create the Product B");
   apb=factory.CreateProductB();
  }

Definieren der Client-Klasse und Ausführen des Musters: 

class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}
void Client::Run(void)
  {
   Print("The client requests to create the Factory 1");
   Print("The client requests to create the Factory client");
   Print("The client requests the Factory client to manage the Factory 1");
   FactoryClient client(new Factory1);
   Print("The client requests the Factory client to operate");
   client.Run();
   Print("The client requests to create the new factory 2 and asks the factory client to switch factories");
   client.Switch(new Factory2);
   Print("The client requests the Factory client to run again");
   client.Run();
  }

Wir können also den gesamten Code in einem Block sehen, wie im Folgenden dargestellt:

namespace AbstractFactory
{
interface AbstractProductA
  {
  };
interface AbstractProductB
  {
   void Interact(AbstractProductA*);
  };
interface AbstractFactory
  {
   AbstractProductA* CreateProductA(void);
   AbstractProductB* CreateProductB(void);
  };
class ProductA1:public AbstractProductA
  {
public:
                     ProductA1(void);
  };
void ProductA1::ProductA1(void) 
{
Print("Product A1 is constructed");
}
class ProductA2:public AbstractProductA
  {
public:
                     ProductA2(void);
  };
void ProductA2::ProductA2(void) 
{
Print("Product A2 is constructed");
}
class ProductB1:public AbstractProductB
  {
public:
                     ProductB1(void);
   void              Interact(AbstractProductA*);
  };
void ProductB1::ProductB1(void) 
{
Print("Product B1 is constructed");
}
void ProductB1::Interact(AbstractProductA*src)
  {
   Print("Product B1: ",&this," is interacting with Product A: ",src);
  }
class ProductB2:public AbstractProductB
  {
public:
                     ProductB2(void);
   void              Interact(AbstractProductA*);
  };
void ProductB2::ProductB2(void) 
{
Print("Product B2 is constructed");
}
void ProductB2::Interact(AbstractProductA*src)
  {
   Print("Product B2: ",&this," is interacting with Product A: ",src);
  }
class Factory1:public AbstractFactory
  {
public:
                     Factory1(void);
   AbstractProductA* CreateProductA(void);
   AbstractProductB* CreateProductB(void);
  };
void Factory1::Factory1(void)
  {
   Print("Factory 1: ",&this," is constructed");
  }
AbstractProductA* Factory1::CreateProductA(void)
  {
   Print("Factory 1 creates and returns Product A1");
   return new ProductA1;
  }
AbstractProductB* Factory1::CreateProductB(void)
  {
   Print("Factory 1 creates and returns Product B1");
   return new ProductB1;
  }
class Factory2:public AbstractFactory
  {
public:
                     Factory2(void);
   AbstractProductA* CreateProductA(void);
   AbstractProductB* CreateProductB(void);
  };
void Factory2::Factory2(void)
  {
   Print("Factory 2: ",&this," is constructed");
  }
AbstractProductA* Factory2::CreateProductA(void)
  {
   Print("Factory 2 creates and returns Product A2");
   return new ProductA2;
  }
AbstractProductB* Factory2::CreateProductB(void)
  {
   Print("Factory 2 creates and returns Product B2");
   return new ProductB2;
  }
class FactoryClient
  {
public:
   void              Run(void);
   void              Switch(AbstractFactory*);
                     FactoryClient(AbstractFactory*);
                    ~FactoryClient(void);
protected:
   AbstractProductA* apa;
   AbstractProductB* apb;
   AbstractFactory*  factory;
   void              Delete(void);
  };
void FactoryClient::FactoryClient(AbstractFactory* af)
  {
   Print("Factory client created and received Abstract Factory ",af);
   Print("Factory client requests to accept/switch the factories");
   Switch(af);
  }
void FactoryClient::~FactoryClient(void)
  {
   Delete();
  }
void FactoryClient::Run(void)
  {
   Print("Factory client runs the abstract Product B");
   apb.Interact(apa);
  }
void FactoryClient::Delete(void)
  {
   delete apa;
   delete apb;
   delete factory;
  }
void FactoryClient::Switch(AbstractFactory *af)
  {
   string sFactory;
   StringConcatenate(sFactory,sFactory,factory);
   int iFactory=(int)StringToInteger(sFactory);
   if(iFactory>0)
     {
      Print("Factory client switches the old factory ",factory," to the new one ",af);
     }
   else
     {
      Print("Factory client accepts the new factory ",af);
     }
   Delete();
   factory=af;
   Print("Factory client saved the new factory");
   Print("Factory client requests its new factory to create the Product A");
   apa=factory.CreateProductA();
   Print("Factory client requests its new factory to create the Product B");
   apb=factory.CreateProductB();
  }
class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}
void Client::Run(void)
  {
   Print("The client requests to create the Factory 1");
   Print("The client requests to create the Factory client");
   Print("The client requests the Factory client to manage the Factory 1");
   FactoryClient client(new Factory1);
   Print("The client requests the Factory client to operate");
   client.Run();
   Print("The client requests to create the new factory 2 and asks the factory client to switch factories");
   client.Switch(new Factory2);
   Print("The client requests the Factory client to run again");
   client.Run();
  }
}


Erbauer

Das Erbauer-Muster (Builder) ist ein Erzeugungsmuster, das verwendet werden kann, wenn komplexe Objekte erstellt werden müssen und die Konstruktion des Objekts von seiner Darstellung getrennt werden soll. Dies kann hilfreich sein, um verschiedene Darstellungen desselben Objekts durch denselben Konstruktionsprozess zu erstellen.

Was bewirkt das Muster?

Das folgende Diagramm zeigt, wie dieses Erzeugungsmuster funktioniert, indem es seine Struktur darstellt:

Erbauer

Wie wir anhand der Struktur des Erbauers sehen können, haben wir den Erbauer, der die Schnittstelle für die Erstellung von Teilen des Produktobjekts spezifiziert, den Director, der das Objekt unter Verwendung der Schnittstelle des Erbauers konstruiert, den ConcreteBuilder, der für die folgenden Aufgaben verwendet werden kann:

  • Konstruieren und montieren der Teile des Produkts durch die Implementierung der Schnittstelle des Erbauers.
  • Definieren der Darstellung und unter Beobachtung halten.
  • Abruf des Produkts durch Bereitstellung der Schnittstelle.

Schließlich haben wir das Produkt, das das komplexe Objekt darstellt, das gebaut wird.

Welches Designproblem wird damit gelöst?

Wir können dieses Muster verwenden, wenn wir Folgendes benötigen:

  • Ein unabhängiger Algorithmus zur Erstellung eines komplexen Objekts aus Komponenten von Teilen des Objekts und deren Zusammenbau.
  • Zulassen verschiedener Darstellungen des Objekts durch den Konstruktionsprozess.

Wir erhalten also Folgendes

  • Auf der Grundlage der internen Darstellung des Produkts gibt uns das Erbauer-Muster die Erlaubnis, sie zu variieren.
  • Durch die Kapselung der Methode zur Konstruktion und Darstellung des komplexen Objekts wird die Modularität verbessert, was bedeutet, dass der Code für Konstruktion und Darstellung isoliert wird.
  • Sie gibt uns eine genauere Kontrolle über den Prozess der Produktherstellung.

Wie können wir es in MQL5 verwenden?

In diesem Teil stellen wir den Code für die Struktur des Erbauer-Musters vor.

Mit der Namespace-Funktion deklarieren wir die Erbauer-Funktion:

namespace Builder

Im Hauptteil der Funktion erstellen wir die Klasse Product wie folgt:

class Product
  {
public:
   void              Add(string);
   void              Show();
protected:
   string            parts[];
  };

Hinzufügen des Teils:

void Product::Add(string part)
  {
   int size=ArraySize(parts);
   ArrayResize(parts,size+1);
   parts[size]=part;
   Print("The product added ",part," to itself");
  }

Anzeige aller Teile des Produkts:

void Product::Add(string part)
  {
   int size=ArraySize(parts);
   ArrayResize(parts,size+1);
   parts[size]=part;
   Print("The product added ",part," to itself");
  }

Erstellung der abstrakten Schnittstelle Erbauer zur Erstellung der Produktteile A, B und C:

interface Builder
  {
   void BuildPartA();
   void BuildPartB();
   void BuildPartC();
   Product* GetResult();
  };

Erstellen der Director-Klasse, die ein Objekt mit der Erbauer-Schnittstelle konstruiert, indem sie die Klassenfunktion:

class Director
  {
public:
   void              Construct();
                     Director(Builder*);
                    ~Director();
protected:
   Builder*          builder;
  };

Erstellen und Empfangen des Erbauers durch den Direktor, indem folgende Funktionen erstellt werden:

void Director::Director(Builder *b)
  {
   builder=b;
   Print("The director created and received the builder ",b);
  }
void Director::~Director(void)
  {
   delete builder;
  }

Beginn der Erstellung der Produktteile A, B und C durch den Direktor:

void Director::Construct(void)
  {
   Print("The director started the construction");
   Print("The director requestd its builder to build the product parts");
   builder.BuildPartA();
   builder.BuildPartB();
   builder.BuildPartC();
   Print("The director's builder constructed the product from parts");
  }

Erstellen der Klasse ConcreteErbauer mit drei öffentlichen Mitgliedern für Teile des Produkts und einem geschützten Mitglieder für das Produkt wie im Folgenden beschrieben:

class ConcreteBuilder:public Builder
  {
public:
   void              BuildPartA();
   void              BuildPartB();
   void              BuildPartC();
   Product*          GetResult();
protected:
   Product           product;
  };

Hinzufügen der A-, B- und C-Teile zum Produkt durch den Konstrukteur und anschließende Rückgabe des Produkts mit Hilfe der folgenden Funktionen:

void ConcreteBuilder::BuildPartA(void)
  {
   Print("The builder requests the product to add part A to itself");
   product.Add("part a");
   Print("The builder made the part of A and added it to the product");
  }
void ConcreteBuilder::BuildPartB(void)
  {
   Print("The builder requests the product to add part B to itself");
   product.Add("part b");
   Print("The builder made the part of B and added it to the product");
  }
void ConcreteBuilder::BuildPartC(void)
  {
   Print("The builder requests the product to add part C to itself");
   product.Add("part c");
   Print("The builder made part C and added it to the product");
  }
Product* ConcreteBuilder::GetResult(void)
  {
   Print("The builder is returns the product");
   return &product;
  }

Erstellen der Client-Klasse mit zwei öffentlichen Mitgliedern für die Konstruktoren Output und Run und anschließendes Ausführen des Clients: 

class Client
  {
public:
   string            Output();
   void              Run();
  };
string Client::Output() {return __FUNCTION__;}
void Client::Run()
  {
   Print("The client requests to create a new concrete builder");
   Builder* builder=new ConcreteBuilder;
   Print("The client requests to create a director and give him the builder");
   Director director(builder);
   Print("The client requests the director to perform the construction");
   director.Construct();
   Print("The client requests the builder to return the result product");
   Product* product=builder.GetResult();
   Print("The client is requests the product to describe itself");
   product.Show();
  }

Der folgende Code ist also der vollständige Code in einem Block für die Erbauer-Struktur:

namespace Builder
{
class Product
  {
public:
   void              Add(string);
   void              Show();
protected:
   string            parts[];
  };
void Product::Add(string part)
  {
   int size=ArraySize(parts);
   ArrayResize(parts,size+1);
   parts[size]=part;
   Print("The product added ",part," to itself");
  }
void Product::Show(void)
  {
   Print("The product shows all parts that it is made of");
   int total=ArraySize(parts);
   for(int i=0; i<total; i++)
      Print(parts[i]);
  }
interface Builder
  {
   void BuildPartA();
   void BuildPartB();
   void BuildPartC();
   Product* GetResult();
  };
class Director
  {
public:
   void              Construct();
                     Director(Builder*);
                    ~Director();
protected:
   Builder*          builder;
  };
void Director::Director(Builder *b)
  {
   builder=b;
   Print("The director created and received the builder ",b);
  }
void Director::~Director(void)
  {
   delete builder;
  }
void Director::Construct(void)
  {
   Print("The director started the construction");
   Print("The director requestd its builder to build the product parts");
   builder.BuildPartA();
   builder.BuildPartB();
   builder.BuildPartC();
   Print("The director's builder constructed the product from parts");
  }
class ConcreteBuilder:public Builder
  {
public:
   void              BuildPartA();
   void              BuildPartB();
   void              BuildPartC();
   Product*          GetResult();
protected:
   Product           product;
  };
void ConcreteBuilder::BuildPartA(void)
  {
   Print("The builder requests the product to add part A to itself");
   product.Add("part a");
   Print("The builder made the part of A and added it to the product");
  }
void ConcreteBuilder::BuildPartB(void)
  {
   Print("The builder requests the product to add part B to itself");
   product.Add("part b");
   Print("The builder made the part of B and added it to the product");
  }
void ConcreteBuilder::BuildPartC(void)
  {
   Print("The builder requests the product to add part C to itself");
   product.Add("part c");
   Print("The builder made part C and added it to the product");
  }
Product* ConcreteBuilder::GetResult(void)
  {
   Print("The builder is returns the product");
   return &product;
  }
class Client
  {
public:
   string            Output();
   void              Run();
  };
string Client::Output() {return __FUNCTION__;}
void Client::Run()
  {
   Print("The client requests to create a new concrete builder");
   Builder* builder=new ConcreteBuilder;
   Print("The client requests to create a director and give him the builder");
   Director director(builder);
   Print("The client requests the director to perform the construction");
   director.Construct();
   Print("The client requests the builder to return the result product");
   Product* product=builder.GetResult();
   Print("The client is requests the product to describe itself");
   product.Show();
  }
}


Fabrikmethode

Das Muster der Fabrikmethode ist ein weiteres Entwurfsmuster, das die Schnittstelle zur Erstellung des Objekts definiert und Unterklassen die Erlaubnis gibt, über die zu instanziierende Klasse zu entscheiden; darüber hinaus ermöglicht es einer Klasse, die Instanziierung auf Unterklassen zu verschieben. Er ist auch als Virtual Constructor bekannt.

Was bewirkt das Muster?

Das folgende Diagramm zeigt die Struktur des Musters der Fabrikmethode:

Fabrikmethode

Wie aus dem vorherigen Diagramm hervorgeht, ergibt sich folgendes Bild:

  • (Product) definiert die Schnittstelle von Objekten, die durch die Fabrikmethode erstellt werden.
  • (ConcreteProduct) ist für die Implementierung der Schnittstelle Product verantwortlich.
  • (Creator) gibt das Produktobjekt nach der Deklaration der Fabrikmethode zurück. Er kann eine Implementierung als Standard für die Fabrikmethode bereitstellen, die das Standardobjekt des ConcreteProduct zurückgibt, und er kann ein Objekt des Produkts durch Aufruf der Fabrikmethode erzeugen.
  • (ConcreteCreator) gibt die ConcreteProduct-Instanz zurück, indem er die Fabrikmethode übersteuert.

Welches Designproblem wird damit gelöst?

Wir können dieses Muster der Fabrikmethoden verwenden, wenn:

  • Wir haben eine Klasse, die nicht vorhersagen kann, welche Klasse von Objekten erstellt werden muss.
  • Die Klasse möchte die Objekte angeben, die von ihren Unterklassen erstellt werden.
  • Eine von mehreren Helper-Unterklassen wird als Verantwortlicher von Klassen delegiert und wir müssen wissen, welche Helper-Unterklasse der Delegierte ist.

Wie können wir es in MQL5 verwenden?

Wir können die Struktur der Fabrikmethode in mql5 als Include-Datei kodieren, wie in den folgenden Schritten.

Durch die Verwendung des Namespace werden wir FactoryMethod deklarieren, um die Funktion der Struktur im Inneren aufzulisten:

namespace FactoryMethod

Erstellen der Schnittstelle des Produktobjekts mit der Fabrikmethode:

interface Product
  {
  };

Erstellung der Klasse ConcreteProduct und Implementierung der Produktschnittstelle:

class ConcreteProduct:public Product
  {
public:
                     ConcreteProduct(void);
  };
ConcreteProduct::ConcreteProduct(void)
  {
   "The concrete product: ",&this," created");
  }

Erstellung der Klasse Creator, Rückgabe des Objekts vom Typ Produkt, Implementierung zur Rückgabe des konkreten Produkts, Erstellung des Produktobjekts:

class Creator
  {
public:
   virtual Product*  FactoryMethod(void)=0;
   void              AnOperation(void);
                    ~Creator(void);
protected:
   Product*          product;
  };
Creator::~Creator(void) {delete product;}
void Creator::AnOperation(void)
  {
   Print("The creator runs its operation");
   delete product;
   product=FactoryMethod();
   Print("The creator saved the product that received from the virtual factory method");
  }

Ausführen der Fabrikmethode, Erstellen und Zurückgeben eines neuen konkreten Produkts:

class ConcreteCreator:public Creator
  {
public:
   Product*          FactoryMethod(void);
  };
Product* ConcreteCreator::FactoryMethod(void)
  {
   Print("The creator runs the factory method");
   Print("The concrete creator creates and returns the new concrete product");
   return new ConcreteProduct;
  }

Erstellen der Client-Klasse mit zwei öffentlichen Mitgliedern Output und Run:

class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}

Ausführen der Client-Klasse, um die Erstellung des Erzeugers anzufordern, das Produkt zurückzugeben und den Vorgang des Erzeugers auszuführen:

void Client::Run(void)
  {
   Print("requests to make the creator");
   ConcreteCreator creator;
   Print("requests the creator to run its factory method to return the product");
   Product* product=creator.FactoryMethod();
   Print("requests the creator to run its operation");
   creator.AnOperation();
   delete product;
  }

Im Folgenden wird der vollständige Code in einem Block dargestellt, um die Struktur der Fabrikmethode darzustellen:

namespace FactoryMethod
{
interface Product
  {
  };
class ConcreteProduct:public Product
  {
public:
                     ConcreteProduct(void);
  };
ConcreteProduct::ConcreteProduct(void)
  {
   Print("The concrete product: ",&this," created");
  }
class Creator
  {
public:
   virtual Product*  FactoryMethod(void)=0;
   void              AnOperation(void);
                    ~Creator(void);
protected:
   Product*          product;
  };
Creator::~Creator(void) {delete product;}
void Creator::AnOperation(void)
  {
   Print("The creator runs its operation");
   delete product;
   product=FactoryMethod();
   Print("The creator saved the product that received from the virtual factory method");
  }
class ConcreteCreator:public Creator
  {
public:
   Product*          FactoryMethod(void);
  };
Product* ConcreteCreator::FactoryMethod(void)
  {
   Print("The creator runs the factory method");
   Print("The concrete creator creates and returns the new concrete product");
   return new ConcreteProduct;
  }
class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}
void Client::Run(void)
  {
   Print("requests to make the creator");
   ConcreteCreator creator;
   Print("requests the creator to run its factory method to return the product");
   Product* product=creator.FactoryMethod();
   Print("requests the creator to run its operation");
   creator.AnOperation();
   delete product;
  }
}


Prototyp

Der Prototyp ist ein weiteres Erzeugungsmuster, das eine Prototyp-Instanz verwendet, um bestimmte Arten von Objekten zu erstellen, und diesen Prototyp dann kopiert, um neue Objekte zu erstellen.

Was bewirkt das Muster?

Das folgende Diagramm zeigt die Struktur des Entwurfsmusters Prototype:

Prototyp

Wie aus dem vorherigen Diagramm hervorgeht, ergibt sich folgendes Bild:

  • (Prototype): Er erstellt die Schnittstelle, die sich selbst klonen kann.
  • (ConcretePrototype): Er klont sich selbst, indem er die Operation dafür implementiert.
  • (Client): Er fordert den Prototyp auf, sich selbst zu klonen, um ein neues Objekt zu erstellen.

Welches Designproblem wird damit gelöst?

Wir können dieses Prototyp-Muster verwenden, wenn:

  • Die Klassen, die wir instanziieren oder erstellen müssen, werden zur Laufzeit festgelegt.
  • Wir müssen vermeiden, die Klassenhierarchie der Fabriken aufzubauen, die parallel zur Klassenhierarchie der Produkte verlaufen kann.
  • Wir haben Klasseninstanzen, die nur eine von wenigen verschiedenen Zustandskombinationen haben können.

Wir können also sagen, dass die Folgen der Anwendung des Musters „Prototype“ die folgenden sind:

  • Es gibt uns die Möglichkeit, Produkte zur Laufzeit einfach hinzuzufügen oder zu entfernen, da der Kunde die Möglichkeit hat, Prototypen zu installieren und zu entfernen.
  • Sie gibt uns die Möglichkeit, neue Objekte zu spezifizieren, indem wir Werte für die Variablen des Objekts angeben.
  • Sie gibt uns die Möglichkeit, neue Objekte durch Strukturvariation zu spezifizieren.
  • Anstatt ein neues Objekt zu erstellen, klont der Prototyp einen Prototyp, was eine Reduktion durch Unterklassen bedeutet.
  • Es hilft, dass die Anwendung mit Klassen dynamisch konfiguriert werden kann.

Wie können wir es in MQL5 verwenden?

Im Folgenden finden Sie eine Methode zum Schreiben des Codes für die Prototyp-Struktur.

Mit dem Schlüsselwort Namespace wird der Prototyp deklariert und alle Funktionen darin aufgelistet:

namespace Prototype

Erstellen der Prototyp-Klasse oder -Schnittstelle, um sich selbst zu klonen:

class Prototype
  {
public:
   virtual Prototype* Clone(void)=0;
                     Prototype(int);
protected:
   int               id;
  };
Prototype::Prototype(int i):id(i)
  {
   Print("The prototype ",&this,", id - ",id," is created");
  }

Erstellen der concretePrototype1, und 2 implementiert die Operation, sich zu klonen:

class ConcretePrototype1:public Prototype
  {
public:
                     ConcretePrototype1(int);
   Prototype*        Clone(void);
  };
ConcretePrototype1::ConcretePrototype1(int i):
   Prototype(i)
  {
   Print("The concrete prototype 1 - ",&this,", id - ",id," is created");
  }
Prototype* ConcretePrototype1::Clone(void)
  {
   Print("The cloning concrete prototype 1 - ",&this,", id - ",id);
   return new ConcretePrototype1(id);
  }
class ConcretePrototype2:public Prototype
  {
public:
                     ConcretePrototype2(int);
   Prototype*        Clone(void);
  };
ConcretePrototype2::ConcretePrototype2(int i):
   Prototype(i)
  {
   Print("The concrete prototype 2 - ",&this,", id - ",id," is created");
  }
Prototype* ConcretePrototype2::Clone(void)
  {
   Print("The cloning concrete prototype 2 - ",&this,", id - ",id);
   return new ConcretePrototype2(id);
  }

Erstellen der Client-Klasse, um ein neues Objekt durch Klonen des Prototyps auf sich selbst zu erstellen:

class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}

Ausführen des Clients, der den Prototyp auffordert, sich selbst zu klonen:

void Client::Run(void)
  {
   Prototype* prototype;
   Prototype* clone;
   Print("requests to create the concrete prototype 1 with id 1");
   prototype=new ConcretePrototype1(1);
   Print("requests the prototype ",prototype," to create its clone");
   clone=prototype.Clone();
   delete prototype;
   delete clone;
   Print("requests to create the concrete prototype 2 with id 2");
   prototype=new ConcretePrototype2(2);
   Print("requests the prototype ",prototype," to create its clone");
   clone=prototype.Clone();
   delete prototype;
   delete clone;
  }

Nachfolgend ist der vollständige Code der Struktur des Musters Prototype, dargestellt in einem Block:

namespace Prototype
{
class Prototype
  {
public:
   virtual Prototype* Clone(void)=0;
                     Prototype(int);
protected:
   int               id;
  };
Prototype::Prototype(int i):id(i)
  {
   Print("The prototype ",&this,", id - ",id," is created");
  }
class ConcretePrototype1:public Prototype
  {
public:
                     ConcretePrototype1(int);
   Prototype*        Clone(void);
  };
ConcretePrototype1::ConcretePrototype1(int i):
   Prototype(i)
  {
   Print("The concrete prototype 1 - ",&this,", id - ",id," is created");
  }
Prototype* ConcretePrototype1::Clone(void)
  {
   Print("The cloning concrete prototype 1 - ",&this,", id - ",id);
   return new ConcretePrototype1(id);
  }
class ConcretePrototype2:public Prototype
  {
public:
                     ConcretePrototype2(int);
   Prototype*        Clone(void);
  };
ConcretePrototype2::ConcretePrototype2(int i):
   Prototype(i)
  {
   Print("The concrete prototype 2 - ",&this,", id - ",id," is created");
  }
Prototype* ConcretePrototype2::Clone(void)
  {
   Print("The cloning concrete prototype 2 - ",&this,", id - ",id);
   return new ConcretePrototype2(id);
  }
class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}
void Client::Run(void)
  {
   Prototype* prototype;
   Prototype* clone;
   Print("requests to create the concrete prototype 1 with id 1");
   prototype=new ConcretePrototype1(1);
   Print("requests the prototype ",prototype," to create its clone");
   clone=prototype.Clone();
   delete prototype;
   delete clone;
   Print("requests to create the concrete prototype 2 with id 2");
   prototype=new ConcretePrototype2(2);
   Print("requests the prototype ",prototype," to create its clone");
   clone=prototype.Clone();
   delete prototype;
   delete clone;
  }
}


Singleton

Der Hauptzweck dieses Musters besteht darin, sicherzustellen, dass es nur eine Instanz einer Klasse und einen Zugriff darauf gibt, indem ein globaler Punkt bereitgestellt wird.

Was bewirkt das Muster?

Im Folgenden ist die Struktur des Singleton-Entwurfsmusters grafisch dargestellt:

Singleton

Wie wir im vorherigen Diagramm sehen können, haben wir die (Singleton), die die Operation der Instanz definiert, die die Erlaubnis für ihre Instanz gibt, um von den Clients zugegriffen zu werden. Dieses Singleton-Muster kann auch für die Erstellung seiner eigenen Instanz verantwortlich sein.

Welches Designproblem wird damit gelöst?

Dieses Singleton-Entwurfsmuster kann verwendet werden, wenn:

  • Es ist obligatorisch, dass es nur eine Klasseninstanz gibt und dass diese für die Kunden über den bekannten Zugangspunkt zugänglich sein muss.
  • Wir benötigen dies als erweiterte Einzelinstanz durch Unterklassifizierung und es kann ohne Änderung verwendet werden.

Nachfolgend sind einige Beispiele für Konsequenzen aufgeführt, die sich aus der Anwendung des Singleton-Musters ergeben können:

  • Aufgrund der Kapselung von der Klasse zu ihrer einzelnen Instanz in diesem Muster kann der Zugriff auf diese Instanz kontrolliert werden.
  • Bei der Anwendung des Singleton-Musters ist man flexibler als bei der Verwendung von Klassenoperationen.

Wie können wir es in MQL5 verwenden?

Im Folgenden werden die Schritte zur Codierung der Struktur des Singleton-Musters in MQL5 beschrieben.

Die Verwendung des Namespace-Schlüsselworts zur Deklaration des Singleton t listet alle Funktionen innerhalb:

namespace Singleton

Erstellen der Singleton-Klasse:

class Singleton
  {
public:
   static Singleton* Instance(void);
   void              SingletonOperation(void);
   string            GetSingletonData(void);
protected:
                     Singleton(void);
   static Singleton* uniqueInstance;
   string            singletonData;
  };
Singleton* Singleton::uniqueInstance=NULL;

Erstellen des Singleton-Objekts:

Singleton::Singleton(void)
  {
   Print("The singleton ",&this," is created");
  }

Ausführen der Singleton-Operation und Festlegen ihrer Daten:

void Singleton::SingletonOperation(void)
  {
   Print("runs the singleton operation > setting singleton data");
   singletonData="singleton data";
  }

Lesen und Abrufen der Singleton-Daten:

string Singleton::GetSingletonData(void)
  {
   Print("reads and returns the singleton data");
   return singletonData;
  }

Abrufen oder Zurückgeben der eindeutigen Instanz:

Singleton* Singleton::Instance(void)
  {
   Print("The singleton instance method runs");
   if(!CheckPointer(uniqueInstance))
     {
      Print("The unique instance of the singleton is an empty");
      uniqueInstance=new Singleton;
      Print("singleton assigned to unique instance");
     }
   Print("The unique instance contains singleton: ",uniqueInstance);
   Print("returns the unique instance ",uniqueInstance," of the singleton");
   return uniqueInstance;
  }

Erstellen der Klasse Client:

class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}

Der Client erhält Zugriff auf das Singleton über die Instanz:

void Client::Run(void)
  {
   Print("requests the singleton instance 1");
   Singleton* instance1=Singleton::Instance();
   Print("requests the singleton instance 2");
   Singleton* instance2=Singleton::Instance();
   string compareInstances=
      (instance1==instance2)?
      "instances 1 and instance 2 are the same objects":
      "instances are different objects";
   Print(compareInstances);
   Print("requests singleton operation on the instance 1");
   instance1.SingletonOperation();
   Print("requests singleton data by the singleton instance 2");
   string singletonData=instance2.GetSingletonData();
   Print(singletonData);
   delete instance1;
  }

Im Folgenden finden Sie den vollständigen Code dieses Singleton-Musters in einem Block:

namespace Singleton
{
class Singleton
  {
public:
   static Singleton* Instance(void);
   void              SingletonOperation(void);
   string            GetSingletonData(void);
protected:
                     Singleton(void);
   static Singleton* uniqueInstance;
   string            singletonData;
  };
Singleton* Singleton::uniqueInstance=NULL;
Singleton::Singleton(void)
  {
   Print("The singleton ",&this," is created");
  }
void Singleton::SingletonOperation(void)
  {
   Print("runs the singleton operation > setting singleton data");
   singletonData="singleton data";
  }
string Singleton::GetSingletonData(void)
  {
   Print("reads and returns the singleton data");
   return singletonData;
  }
Singleton* Singleton::Instance(void)
  {
   Print("The singleton instance method runs");
   if(!CheckPointer(uniqueInstance))
     {
      Print("The unique instance of the singleton is an empty");
      uniqueInstance=new Singleton;
      Print("singleton assigned to unique instance");
     }
   Print("The unique instance contains singleton: ",uniqueInstance);
   Print("returns the unique instance ",uniqueInstance," of the singleton");
   return uniqueInstance;
  }
class Client
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}
void Client::Run(void)
  {
   Print("requests the singleton instance 1");
   Singleton* instance1=Singleton::Instance();
   Print("requests the singleton instance 2");
   Singleton* instance2=Singleton::Instance();
   string compareInstances=
      (instance1==instance2)?
      "instances 1 and instance 2 are the same objects":
      "instances are different objects";
   Print(compareInstances);
   Print("requests singleton operation on the instance 1");
   instance1.SingletonOperation();
   Print("requests singleton data by the singleton instance 2");
   string singletonData=instance2.GetSingletonData();
   Print(singletonData);
   delete instance1;
  }
}


Schlussfolgerung

Am Ende dieses Artikels haben wir einfache Informationen über das Thema Entwurfsmuster gegeben und den Typ der Erzeugungsmuster kennengelernt, der uns hilft, Objekte zu erstellen, die wiederverwendbar, erweiterbar und testbar sind, oder mit anderen Worten: Muster, die uns helfen, einen sauberen Code zu schreiben.

Wir haben die folgenden Erzeugungsmuster identifiziert:

  • Abstrakte Fabrik
  • Erbauer
  • Fabrikmethode
  • Prototyp
  • Singleton

Wir haben über die vorhergehenden Erzeugungsmuster gelernt, nachdem wir herausgefunden haben, was Entwurfsmuster sind, inwieweit sie in unserer Software nützlich sein können, wenn wir objektorientierte Software schreiben, welche Strukturen diese Entwurfsmuster haben und welche Software- oder Designprobleme durch Entwurfsmuster gelöst werden können.

Das Thema Entwurfsmuster ist ein wichtiges Thema in der Softwareentwicklung und Ihr gutes Verständnis und die Verwendung von Konzepten wird Ihnen sehr bei der Softwareentwicklung helfen und viele Probleme lösen, die in Ihrem Code auftreten können. Ich empfehle daher, mehr über dieses wichtige Thema zu lesen und zu lernen, um alle Probleme, die durch eines dieser Entwurfsmuster gelöst werden können, zu überwinden, indem man das Rad neu erfindet.

Im Folgenden finden Sie Ressourcen, die Sie nutzen können, um mehr zu erfahren:

  • Design Patterns - Elements of Reusable Object-Oriented Software von Eric Gamma, Richard Helm, Ralph Johnson, and John Vlissides
  • Design Patterns for Dummies von Steve Holzner
  • Head First Design Patterns von Eric Freeman, Elisabeth Robson, Bert Bates, and Kathy Sierra

Ich hoffe, dass Sie diesen Artikel nützlich fanden und etwas Neues über das Thema Entwurfsmuster gelernt haben. Ich hoffe auch, dass dieser Artikel Sie ermutigt, mehr über dieses interessante Thema zu lernen, das ein Game Changer in Ihrem Code sein kann. Es ist auch sehr wichtig, zuerst über die objektorientierte Programmierung (OOP) zu lernen, weil Sie dann das Thema Entwurfsmuster gut verstehen werden. Sie können meinen früheren Artikel über das Verständnis der objektorientierten Programmierung (OOP) von MQL5 lesen. Wenn Sie auch mehr darüber lesen möchten, wie Sie Handelssysteme auf der Grundlage der beliebtesten technischen Indikatoren in MQL5 und andere Themen über MQL5 entwerfen können, können Sie mehr darüber durch meine Publikationen Seite lesen und Sie werden viele Artikel darüber finden, und ich hoffe, dass Sie sie nützlich für Sie finden.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/13622

Beigefügte Dateien |
Builder.mqh (3 KB)
Factory_Method.mqh (1.51 KB)
Prototype.mqh (3.78 KB)
Singleton.mqh (2.01 KB)
Datenwissenschaft und maschinelles Lernen (Teil 15): SVM, ein Muss im Werkzeugkasten jedes Händlers Datenwissenschaft und maschinelles Lernen (Teil 15): SVM, ein Muss im Werkzeugkasten jedes Händlers
Entdecken Sie die unverzichtbare Rolle von Support Vector Machines (SVM) bei der Gestaltung der Zukunft des Handels. Dieser umfassende Leitfaden zeigt auf, wie SVM Ihre Handelsstrategien verbessern, die Entscheidungsfindung optimieren und neue Chancen auf den Finanzmärkten erschließen kann. Tauchen Sie ein in die Welt der SVM mit realen Anwendungen, Schritt-für-Schritt-Tutorials und Expertenwissen. Rüsten Sie sich mit dem unverzichtbaren Werkzeug aus, das Ihnen helfen kann, die Komplexität des modernen Handels zu bewältigen. Verbessern Sie das Spiel Ihres Handels mit SVM - ein Muss für den Werkzeugkasten eines jeden Händlers.
Die visuelle Programmiersprache DRAKON - Kommunikationswerkzeug für MQL-Entwickler und Kunden Die visuelle Programmiersprache DRAKON - Kommunikationswerkzeug für MQL-Entwickler und Kunden
DRAKON ist eine visuelle Programmiersprache, die entwickelt wurde, um die Interaktion zwischen Fachleuten aus verschiedenen Bereichen (Biologen, Physiker, Ingenieure...) und Programmierern in russischen Raumfahrtprojekten (z.B. im Projekt für das wiederverwendbare Raumschiff Buran) zu vereinfachen. In diesem Artikel werde ich darüber sprechen, wie DRAKON die Erstellung von Algorithmen zugänglich und intuitiv macht, selbst wenn Sie noch nie mit Code in Berührung gekommen sind, und wie es für Kunden einfacher ist, ihre Gedanken zu erklären, wenn sie Handelsroboter bestellen, und für Programmierer, weniger Fehler bei komplexen Funktionen zu machen.
Entwicklung eines MQTT-Clients für Metatrader 5: ein TDD-Ansatz — Teil 4 Entwicklung eines MQTT-Clients für Metatrader 5: ein TDD-Ansatz — Teil 4
Dieser Artikel ist der vierte Teil einer Serie, die unsere Entwicklungsschritte für einen nativen MQL5-Client für das MQTT-Protokoll beschreibt. In diesem Teil beschreiben wir, was MQTT v5.0 Properties sind, ihre Semantik, wie wir einige von ihnen lesen, und geben ein kurzes Beispiel, wie die Eigenschaften (Properties) zur Erweiterung des Protokolls verwendet werden können.
Der Handel von Paaren Der Handel von Paaren
In diesem Artikel werden wir uns mit dem Handel von Paaren befassen, d. h. mit den Grundsätzen und den Aussichten für seine praktische Anwendung. Wir werden auch versuchen, dafür eine Handelsstrategie zu entwickeln.