Skip to content

Commit 24e98af

Browse files
committed
Add the AbstractFactoryPattern / also make changes in the FactoryMethod
1 parent 23c5a02 commit 24e98af

5 files changed

Lines changed: 187 additions & 36 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ set(APP_SOURCES
111111
"src/patterns/behavioral/Observer.cpp"
112112
"src/patterns/creational/Singleton.cpp"
113113
"src/patterns/creational/FactoryMethod.cpp"
114+
"src/patterns/creational/AbstractFactory.cpp"
114115
"src/patterns/creational/Builder.cpp"
115116
"src/patterns/creational/Prototype.cpp"
116117
)

docs/uml/patterns_creational_abstractfactory.drawio.svg

Lines changed: 4 additions & 0 deletions
Loading

docs/uml/patterns_creational_factorymethod.drawio.svg

Lines changed: 1 addition & 1 deletion
Loading

src/patterns/creational/AbstractFactory.cpp

Lines changed: 156 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,164 @@
1010
// (**) when you have a class with a set of Factory Methods that blur its
1111
// primary responsibility.
1212

13-
// UML: docs/uml/patterns_behavioral_iterator.drawio.svg
13+
// UML: docs/uml/patterns_creational_abstractfactory.drawio.svg
1414

1515
#include <iostream>
16+
#include <string>
17+
namespace {
18+
namespace AbstractFactory {
19+
/**
20+
* The Product interface declares the operations that all concrete products must
21+
* implement.
22+
*/
23+
class IGdbProduct {
24+
public:
25+
virtual ~IGdbProduct() = default;
26+
virtual void launch() const = 0;
27+
};
1628

17-
namespace {}
29+
/**
30+
* Concrete Products provide various implementations of the Product interface.
31+
*/
32+
class LinuxGdbProduct : public IGdbProduct {
33+
public:
34+
void launch() const override {
35+
std::cout
36+
<< "\tsudo apt update && sudo apt install -y gdb && gdb --version\n";
37+
}
38+
};
1839

19-
// struct SingletonAutoRunner
20-
// {
21-
// SingletonAutoRunner()
22-
// {
23-
// std::cout << "\n--- Singleton Pattern Example ---\n";
24-
// }
25-
// };
40+
class WindowsGdbProduct : public IGdbProduct {
41+
public:
42+
void launch() const override {
43+
std::cout << "\tpacman -Syu mingw-w64-x86_64-gdb && gdb --version\n";
44+
}
45+
};
2646

27-
// static SingletonAutoRunner instance;
47+
class MacOsGdbProduct : public IGdbProduct {
48+
public:
49+
void launch() const override {
50+
std::cout << "\tbrew install gdb && gdb --version\n";
51+
}
52+
};
53+
54+
class ICMakeProduct {
55+
public:
56+
virtual ~ICMakeProduct() = default;
57+
virtual void launch() const = 0;
58+
};
59+
60+
class LinuxCMakeProduct : public ICMakeProduct {
61+
public:
62+
void launch() const override {
63+
std::cout << "\tsudo apt update && sudo apt install -y cmake && cmake "
64+
"--version\n";
65+
}
66+
};
67+
68+
class WindowsCMakeProduct : public ICMakeProduct {
69+
public:
70+
void launch() const override {
71+
std::cout << "\tpacman -Syu cmake && cmake --version\n";
72+
}
73+
};
74+
75+
class MacOsCMakeProduct : public ICMakeProduct {
76+
public:
77+
void launch() const override {
78+
std::cout << "\tbrew install cmake && cmake --version\n";
79+
}
80+
};
81+
82+
// ===================================================================================
83+
84+
/*
85+
* Abstract Factory
86+
* provides an abstract interface for creating a family of products
87+
*/
88+
class IProductAbstractFactory {
89+
public:
90+
virtual ~IProductAbstractFactory() = default;
91+
virtual IGdbProduct* createGdbProduct() = 0;
92+
virtual ICMakeProduct* createCMakeProduct() = 0;
93+
};
94+
95+
/*
96+
* Concrete Factory
97+
* each concrete factory create a family of products and client uses
98+
* one of these factories so it never has to instantiate a product object
99+
*/
100+
class WindowsProductFactory : public IProductAbstractFactory {
101+
public:
102+
IGdbProduct* createGdbProduct() override { return new WindowsGdbProduct(); }
103+
ICMakeProduct* createCMakeProduct() override {
104+
return new WindowsCMakeProduct();
105+
}
106+
};
107+
108+
class LinuxProductFactory : public IProductAbstractFactory {
109+
public:
110+
IGdbProduct* createGdbProduct() override { return new LinuxGdbProduct(); }
111+
ICMakeProduct* createCMakeProduct() override {
112+
return new LinuxCMakeProduct();
113+
}
114+
};
115+
116+
class MacOsProductFactory : public IProductAbstractFactory {
117+
public:
118+
IGdbProduct* createGdbProduct() override { return new MacOsGdbProduct(); }
119+
ICMakeProduct* createCMakeProduct() override {
120+
return new MacOsCMakeProduct();
121+
}
122+
};
123+
124+
// ===================================================================================
125+
126+
/**
127+
* The client code works with factories and products only through abstract
128+
* types: AbstractFactory and AbstractProduct. This lets you pass any factory or
129+
* product subclass to the client code without breaking it.
130+
*/
131+
namespace ClientCode {
132+
void clientCode(IProductAbstractFactory* f) {
133+
ICMakeProduct* cmake = f->createCMakeProduct();
134+
IGdbProduct* gdb = f->createGdbProduct();
135+
cmake->launch();
136+
gdb->launch();
137+
138+
delete cmake;
139+
delete gdb;
140+
}
141+
} // namespace ClientCode
142+
143+
// static redudant inside anonymous namespace
144+
IProductAbstractFactory* createProductFactory(const std::string& os) {
145+
if (os == "linux") {
146+
return new LinuxProductFactory();
147+
} else if (os == "windows") {
148+
return new WindowsProductFactory();
149+
} else if (os == "macos") {
150+
return new MacOsProductFactory();
151+
} else {
152+
std::cout << "OS not support yet - " << os << "\n";
153+
return nullptr;
154+
}
155+
}
156+
157+
void run() {
158+
std::string os = "linux";
159+
IProductAbstractFactory* factory = createProductFactory(os);
160+
ClientCode::clientCode(factory);
161+
delete factory;
162+
}
163+
} // namespace AbstractFactory
164+
} // namespace
165+
166+
struct AbstractFactoryAutoRunner {
167+
AbstractFactoryAutoRunner() {
168+
std::cout << "\n--- AbstractFactory Pattern Example ---\n";
169+
AbstractFactory::run();
170+
}
171+
};
172+
173+
static AbstractFactoryAutoRunner instance;

src/patterns/creational/FactoryMethod.cpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,23 @@ class MacOsGdbProduct : public IGdbProduct {
5151
}
5252
};
5353

54+
// ===================================================================================
55+
5456
/**
5557
* The Creator class declares the factory method that is supposed to return an
5658
* object of a Product class. The Creator's subclasses usually provide the
57-
* implementation of this method.
59+
* implementation of this method. (a.k.a IGdbFactory)
5860
*/
59-
class IGdbCreator {
61+
class IGdbFactory {
6062
public:
61-
virtual ~IGdbCreator() = default;
63+
virtual ~IGdbFactory() = default;
6264
virtual IGdbProduct* factoryMethod() = 0;
6365
virtual void launchGdb() = 0;
6466
};
6567

66-
class AbstractGdbCreater : public IGdbCreator {
68+
class AbstractGdbFactory : public IGdbFactory {
6769
public:
68-
// Call the factory method to create a Product object.
69-
70+
// Call the factory method to create a Product object.
7071
void launchGdb() override final {
7172
IGdbProduct* gdb = this->factoryMethod();
7273
gdb->launch();
@@ -78,52 +79,51 @@ class AbstractGdbCreater : public IGdbCreator {
7879
* Concrete Creators override the factory method in order to change the
7980
* resulting product's type.
8081
*/
81-
class WindowsGdbCreator : public AbstractGdbCreater {
82+
class WindowsGdbFactory : public AbstractGdbFactory {
8283
public:
8384
IGdbProduct* factoryMethod() override { return new WindowsGdbProduct(); }
8485
};
8586

86-
class LinuxGdbCreator : public AbstractGdbCreater {
87+
class LinuxGdbFactory : public AbstractGdbFactory {
8788
public:
8889
IGdbProduct* factoryMethod() override { return new LinuxGdbProduct(); }
8990
};
9091

91-
class MacOsGdbCreator : public AbstractGdbCreater {
92+
class MacOsGdbFactory : public AbstractGdbFactory {
9293
public:
9394
IGdbProduct* factoryMethod() override { return new MacOsGdbProduct(); }
9495
};
9596

97+
// ===================================================================================
98+
9699
/**
97100
* The client code works with an instance of a concrete creator, albeit through
98101
* its base interface. As long as the client keeps working with the creator via
99102
* the base interface, you can pass it any creator's subclass.
100103
*/
101104
namespace ClientCode {
102-
void clientCode(IGdbCreator* gdb) {
105+
void clientCode(IGdbFactory* gdb) {
103106
if (gdb != nullptr)
104107
gdb->launchGdb();
105108
}
106109
} // namespace ClientCode
107110

108-
class GdbCreatorFactory {
109-
public:
110-
static IGdbCreator* createGdbCreator(const std::string& os) {
111-
if (os == "linux") {
112-
return new LinuxGdbCreator();
113-
} else if (os == "windows") {
114-
return new WindowsGdbCreator();
115-
} else if (os == "macos") {
116-
return new MacOsGdbCreator();
117-
} else {
118-
std::cout << "OS not support yet - " << os << "\n";
119-
return nullptr;
120-
}
111+
IGdbFactory* createGdbFactory(const std::string& os) {
112+
if (os == "linux") {
113+
return new LinuxGdbFactory();
114+
} else if (os == "windows") {
115+
return new WindowsGdbFactory();
116+
} else if (os == "macos") {
117+
return new MacOsGdbFactory();
118+
} else {
119+
std::cout << "OS not support yet - " << os << "\n";
120+
return nullptr;
121121
}
122-
};
122+
}
123123

124124
void run() {
125125
std::string os = "linux";
126-
IGdbCreator* gdb = GdbCreatorFactory::createGdbCreator(os);
126+
IGdbFactory* gdb = createGdbFactory(os);
127127
ClientCode::clientCode(gdb);
128128
delete gdb;
129129
}

0 commit comments

Comments
 (0)