C++ Factory-Methode
- Factory-Methode in C++
- Einfache Konstruktorklasse in C++
- Verwenden Sie die Factory-Methode für die Konstruktorklasse in C++
- Konkrete Klassen und abstrakte Fabrikmethoden in C++
Die Factory-Methode ist ein Entwurfsmuster für die Objekterstellung in C++, mit dem Objekte erstellt werden, während ihre Zusammensetzung verborgen wird, sodass der Benutzer die Schnittstelle verwenden kann, ohne einen Methodenaufruf zu sehen.
Factory-Methode in C++
Fabriken sind virtuelle Konstruktoren, die es einem Programmierer ermöglichen, Programme zu entwerfen, die es dem Benutzer ermöglichen, mit einer sauberen Programmschnittstelle zu interagieren. Dies bedeutet, dass die Objekterstellung selbst in der übergeordneten Klasse versteckt wird.
Wenn ein Programm zwei Klassen hat, eine Elternklasse und eine Benutzerunterklasse, führt die Verwendung des Konstruktors dazu, dass die beiden Klassen stark voneinander abhängig sind. Jede Änderung, die innerhalb der Elternklasse herbeigeführt wird, führt zu nachfolgenden Änderungen in den Unterklassen.
Das Merkmal von Factories ist die Fähigkeit, die Objekte beim Start des Programms anzugeben, und eröffnet die Möglichkeit, neue Objekte hinzuzufügen, da alle erforderlichen Änderungen nur innerhalb der Bibliotheksklasse und nirgendwo anders vorgenommen werden.
Einfache Konstruktorklasse in C++
Code:
#include <iostream>
using namespace std;
// LIBRARY/PARENT(Wire_Sizes) CLASS WITH Two_mm and Four_mm sub-classes
class Wire_Sizes {
public:
virtual void Diameter() = 0;
};
class Two_mm : public Wire_Sizes {
public:
void Diameter() { cout << "This wire is 2mm in diameter" << endl; }
};
class Four_mm : public Wire_Sizes {
public:
void Diameter() { cout << "This wire is 4mm in diameter" << endl; }
};
// CLIENT(User) CLASS
// One thing to note here is that object creation takes place inside the User
// class, which can affect the whole program if changes are to be made to the
// parent class - like adding a new category of wire diameter.
// In this client class, adding a new type will mean adding a new category to
// the existing if-else ladder.
class User {
public:
User(int type) {
// Client explicitly creates classes according to type
if (type == 1)
pDiameter = new Two_mm();
else if (type == 2)
pDiameter = new Four_mm();
else
pDiameter = NULL;
}
~User() {
if (pDiameter) {
delete[] pDiameter;
pDiameter = NULL;
}
}
Wire_Sizes *getDiameter() { return pDiameter; }
private:
Wire_Sizes *pDiameter;
};
// MAIN FUNCTION
int main() {
User *pClient = new User(2);
Wire_Sizes *pDiameter = pClient->getDiameter();
pDiameter->Diameter();
return 0;
}
Ausgang:
This wire is 4mm in diameter
Die Wire_Sizes
ist die Bibliothek oder die übergeordnete Klasse mit zwei Unterklassen, Two_mm
und Four_mm
, wobei die Methode Diameter()
überladen ist und eine Druckanweisung zurückgibt, wenn die Methode aufgerufen wird.
In der Klasse User
übernimmt der Parametertyp den übergebenen Wert von der Funktion main()
und erstellt eine Objektklasse, die dem Rückgabetyp entspricht. Der ~User()
(Destruktor) zerstört die zugewiesenen Ressourcen und löscht den Zeiger.
Die Funktion main()
erstellt das Objekt *pClient
und übergibt ihm den Wert 2
. Dieser Wert wird an die Klasse User
(Client) übergeben, die ein Objekt des Typs 2
erstellt und dann die entsprechende Methode des Typs 2
aus der Klasse Wire_Sizes
(Eltern) aufruft.
Dies macht das Programm stark abhängig von seinen Unterklassen und macht den Code intensiv. Fabriken werden verwendet, um dieses Problem zu lösen.
Verwenden Sie die Factory-Methode für die Konstruktorklasse in C++
Code:
#include <iostream>
using namespace std;
// The three derived classes, Size_two_mm, Size_three_mm, and Size_four_mm,
// contains the printDiameter() method, which is overloaded in all the
// subclasses
enum Size { Size_two_mm, Size_three_mm, Size_four_mm };
class Wire_Sizes {
public:
virtual void printDiameter() = 0;
static Wire_Sizes* Create(Size type);
};
class Twomm : public Wire_Sizes {
public:
void printDiameter() { cout << "This wire is 2mm in diameter" << endl; }
};
class Threemm : public Wire_Sizes {
public:
void printDiameter() { cout << "This wire is 3mm in diameter" << endl; }
};
class Fourmm : public Wire_Sizes {
public:
void printDiameter() { cout << "This wire is 4mm in diameter" << endl; }
};
Wire_Sizes* Wire_Sizes::Create(Size type) {
if (type == Size_two_mm)
return new Twomm();
else if (type == Size_three_mm)
return new Threemm();
else if (type == Size_four_mm)
return new Fourmm();
else
return NULL;
}
class user {
public:
user() {
Size type = Size_three_mm;
pDiameter = Wire_Sizes::Create(type);
}
~user() {
if (pDiameter) {
delete[] pDiameter;
pDiameter = NULL;
}
}
Wire_Sizes* getDiameter() { return pDiameter; }
private:
Wire_Sizes* pDiameter;
};
int main() {
user* pClient = new user();
Wire_Sizes* pDiameter = pClient->getDiameter();
pDiameter->printDiameter();
return 0;
}
Ausgang:
This wire is 3mm in diameter
Geben Sie in den Aufzählungsdaten Size
zunächst drei Objekte ein, die im Programm verwendet werden.
Die if-else
-Bedingung wird in einen neuen Konstruktor Create()
direkt nach der Klasse Wire_Sizes
(Bibliothek) geschrieben. Das Hinzufügen eines neuen Objekts ist einfacher als das Ändern der Client-Klasse.
Der Konstruktor übernimmt einen Wert mit dem Parameter type
und vergleicht ihn mit der if-else
-Leiter. Bei positiver Übereinstimmung wird die entsprechende Funktion aufgerufen, bei negativer Übereinstimmung wird NULL
zurückgegeben.
Die Klasse user
erstellt nicht explizit Objekte, sondern übergibt den Typ an die Factory-Methode Create()
. Das Objekt Size_three_mm
wird an type übergeben und mittels Zuweisungsoperator wird pDiameter
die Konstruktorklasse Create()
zugewiesen.
Der ~user()
(Destruktor) zerstört die am Ende der Klasse allokierte Ressource und weist der Variable pDiameter
NULL
zu. Innerhalb des Konstruktors getDiameter
wird die Variable pDiameter
zurückgegeben.
Die Methode main()
erstellt das Objekt *pClient
der Klasse user
und dieses Objekt wird Methode pDiameter()
genannt. Die Methode getDiameter()
gibt die Variable pDiameter
zurück, deren Wert im Typ gespeichert ist.
Die Syntax Wire_Sizes * pDiameter = pClient->getDiameter();
Übergeben Sie die Werte der Methode getDiameter()
an pDiameter
, das NULL
speichert, und die Methode printDiameter()
wird aufgerufen.
Konkrete Klassen und abstrakte Fabrikmethoden in C++
Wenn eine Methode oder Klasse deklariert wird, wird sie als abstrakte Klasse bezeichnet, da sie nichts zurückgeben kann, und wenn diese Methode oder Klasse definiert ist, wird sie als konkret bezeichnet. Konkrete Klassen können je nach Anforderung innerhalb einer Factory instanziiert und aufgerufen werden.
Code:
#include <iostream>
using namespace std;
// BASE CLASS
class Concrete_Example {
public:
virtual ~Concrete_Example() {}
virtual std::string Operation() const = 0;
};
class ExampleProduct1 : public Concrete_Example {
public:
std::string Operation() const override {
return "{Product 1 is instantiated}";
}
};
class ExampleProduct2 : public Concrete_Example {
public:
std::string Operation() const override {
return "{Product 2 is instantiated}";
}
};
// CREATOR CLASS
class Create {
public:
virtual ~Create(){};
virtual Concrete_Example* FactoryMethod() const = 0;
std::string SomeOperation() const {
Concrete_Example* concrete_Example = this->FactoryMethod();
std::string result = "Client Code" + concrete_Example->Operation();
delete concrete_Example;
return result;
}
};
class ExampleCreator1 : public Create {
public:
Concrete_Example* FactoryMethod() const override {
return new ExampleProduct1();
}
};
class ExampleCreator2 : public Create {
public:
Concrete_Example* FactoryMethod() const override {
return new ExampleProduct2();
}
};
// USER CLASS
void User(const Create& create) {
std::cout << "User Method is called\n" << create.SomeOperation() << std::endl;
}
// MAIN FUNCTION
int main() {
std::cout << "App: Launched with the ConcreteCreator1.\n";
Create* create = new ExampleCreator1();
User(*create);
std::cout << std::endl;
std::cout << "App: Launched with the ConcreteCreator2.\n";
Create* create2 = new ExampleCreator2();
User(*create2);
delete create;
delete create2;
return 0;
}
Ausgang:
App: Launched with the ConcreteCreator1.
User Method is called
Client Code{Product 1 is instantiated}
App: Launched with the ConcreteCreator2.
User Method is called
Client Code{Product 2 is instantiated}
In diesem Beispiel werden zwei konkrete Klassen innerhalb einer Factory-Klasse erstellt und es wird beobachtet, wie die Factory Klassen aufruft. Die Klasse Concrete_Example
(Basis) bietet viele Implementierungen für das Produkt und seine Schnittstelle.
Die Klasse Concrete_Example
hat zwei Unterklassen – ExampleProduct1
und ExampleProduct2
, die die Produkte enthalten, die die Klasse user
aufrufen möchte. Das Folgende ist die Klasse Create
(Creator) mit einer spezifischen Implementierung - Durch Deklarieren der Factory-Methode wird ein Objekt von einer Produktklasse an die Klasse user
übergeben.
Die Unterklassen werden erstellt, um das Objekt zurückzugeben und die Methoden für diesen Zweck zu implementieren. Obwohl der Klassenname erstellt wird, werden in dieser Klasse oder ihren Unterklassen keine neuen Objekte erstellt.
Der Hauptzweck der Klasse Create
besteht darin, die Produkte aus der Factory-Methode zurückzugeben. Die Unterklassen können die Methode überschreiben und dem Produkt eine neue Implementierung hinzufügen.
Innerhalb der Methode SomeOperation
wird ein Objekt aus der Factory-Methode Concrete_Example
erstellt, und das Objekt wird verwendet, um Änderungen am Produkt zu implementieren. Es kann beobachtet werden, dass die Unterklassen dem Produkt Änderungen zufügen, indem sie die Factory-Methode überschreiben.
Der hier verwendete Client-Code verwendet die Instanz der Klasse create
und ihre Unterklassen, um Methoden aufzurufen, wodurch er unabhängig von der Erstellung von Objekten ist. Nach der Einrichtung oder Umgebung wählt die Anwendung einen Erstellertyp aus.
Die Hauptfunktion verwendet classCreate
, um ein Objekt der Unterklasse ExampleCreator1()
zu bilden. Beide Creator-Methoden werden in diesem Programm mit Objekten aufgerufen, die aus der Klasse Create
erstellt wurden, und nach der Implementierung werden alle erstellten Objekte zerstört.