Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ set(APP_SOURCES
"src/patterns/behavioral/Observer.cpp"
"src/patterns/creational/Singleton.cpp"
"src/patterns/creational/FactoryMethod.cpp"
"src/patterns/creational/AbstractFactory.cpp"
"src/patterns/creational/Builder.cpp"
"src/patterns/creational/Prototype.cpp"
)

# Test files
Expand Down
4 changes: 4 additions & 0 deletions docs/uml/patterns_creational_abstractfactory.drawio.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/uml/patterns_creational_factorymethod.drawio.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions docs/uml/patterns_creational_prototype.drawio.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/core/datatypes/class/CConstructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ void constructers() {
}
} // namespace Move

struct CConstructorsAutoRuner {
CConstructorsAutoRuner() {
struct CConstructorsAutoRunner {
CConstructorsAutoRunner() {
InitializerList::constructers();
Default::constructers();
Delegate::constructors();
Expand All @@ -312,4 +312,4 @@ struct CConstructorsAutoRuner {
}
};

static CConstructorsAutoRuner instance;
static CConstructorsAutoRunner instance;
6 changes: 3 additions & 3 deletions src/core/datatypes/class/CDestructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ void destructers() {
}
} // namespace Virtual

struct CDestructorsAutoRuner {
CDestructorsAutoRuner() {
struct CDestructorsAutoRunner {
CDestructorsAutoRunner() {
Basic::destructers();
Virtual::destructers();
}
};

static CDestructorsAutoRuner instance;
static CDestructorsAutoRunner instance;
8 changes: 4 additions & 4 deletions src/core/datatypes/class/RoleOfThreeFiveZero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class Model {
// noexcept is a specifier that indicates a function will not throw
// exceptions.
Model(Model&& other) noexcept
: cstring(std::exchange(other.cstring, nullptr)){};
: cstring(std::exchange(other.cstring, nullptr)) {};

// V. move assignment
Model& operator=(Model&& other) noexcept {
Expand Down Expand Up @@ -271,14 +271,14 @@ void run() {
}
} // namespace RoleOfZero
} // namespace
struct RoleOfThreeFiveZeroAutoRuner {
struct RoleOfThreeFiveZeroAutoRunner {
// Virtual default destructor: Does not break Rule of Three, Five, or Zero
RoleOfThreeFiveZeroAutoRuner() {
RoleOfThreeFiveZeroAutoRunner() {
Problem::run();
RoleOfThree::run();
RoleOfFive::run();
RoleOfZero::run();
}
};

static RoleOfThreeFiveZeroAutoRuner instance;
static RoleOfThreeFiveZeroAutoRunner instance;
170 changes: 158 additions & 12 deletions src/patterns/creational/AbstractFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,170 @@
// families of related objects without specifying their concrete classes.
// Appicability:
// (*) when your code needs to work with various families of related products,
// but you don’t want it to depend on the concrete classes
// but you don’t want it to depend on the concrete classes
// of those products—they might be unknown beforehand or you simply want to
// allow for future extensibility.
// (**) when you have a class with a set of Factory Methods that blur its
// primary responsibility.
// primary responsibility.

// UML: docs/uml/patterns_behavioral_iterator.drawio.svg
// UML: docs/uml/patterns_creational_abstractfactory.drawio.svg

#include <iostream>
#include <string>
namespace {
namespace AbstractFactory {
/**
* The Product interface declares the operations that all concrete products must
* implement.
*/
class IGdbProduct {
public:
virtual ~IGdbProduct() = default;
virtual void launch() const = 0;
};

namespace {}
/**
* Concrete Products provide various implementations of the Product interface.
*/
class LinuxGdbProduct : public IGdbProduct {
public:
void launch() const override {
std::cout
<< "\tsudo apt update && sudo apt install -y gdb && gdb --version\n";
}
};

// struct SingletonAutoRuner
// {
// SingletonAutoRuner()
// {
// std::cout << "\n--- Singleton Pattern Example ---\n";
// }
// };
class WindowsGdbProduct : public IGdbProduct {
public:
void launch() const override {
std::cout << "\tpacman -Syu mingw-w64-x86_64-gdb && gdb --version\n";
}
};

// static SingletonAutoRuner instance;
class MacOsGdbProduct : public IGdbProduct {
public:
void launch() const override {
std::cout << "\tbrew install gdb && gdb --version\n";
}
};

class ICMakeProduct {
public:
virtual ~ICMakeProduct() = default;
virtual void launch() const = 0;
};

class LinuxCMakeProduct : public ICMakeProduct {
public:
void launch() const override {
std::cout << "\tsudo apt update && sudo apt install -y cmake && cmake "
"--version\n";
}
};

class WindowsCMakeProduct : public ICMakeProduct {
public:
void launch() const override {
std::cout << "\tpacman -Syu cmake && cmake --version\n";
}
};

class MacOsCMakeProduct : public ICMakeProduct {
public:
void launch() const override {
std::cout << "\tbrew install cmake && cmake --version\n";
}
};

// ===================================================================================

/*
* Abstract Factory
* provides an abstract interface for creating a family of products
*/
class IProductAbstractFactory {
public:
virtual ~IProductAbstractFactory() = default;
virtual IGdbProduct* createGdbProduct() = 0;
virtual ICMakeProduct* createCMakeProduct() = 0;
};

/*
* Concrete Factory
* each concrete factory create a family of products and client uses
* one of these factories so it never has to instantiate a product object
*/
class WindowsProductFactory : public IProductAbstractFactory {
public:
IGdbProduct* createGdbProduct() override { return new WindowsGdbProduct(); }
ICMakeProduct* createCMakeProduct() override {
return new WindowsCMakeProduct();
}
};

class LinuxProductFactory : public IProductAbstractFactory {
public:
IGdbProduct* createGdbProduct() override { return new LinuxGdbProduct(); }
ICMakeProduct* createCMakeProduct() override {
return new LinuxCMakeProduct();
}
};

class MacOsProductFactory : public IProductAbstractFactory {
public:
IGdbProduct* createGdbProduct() override { return new MacOsGdbProduct(); }
ICMakeProduct* createCMakeProduct() override {
return new MacOsCMakeProduct();
}
};

// ===================================================================================

/**
* The client code works with factories and products only through abstract
* types: AbstractFactory and AbstractProduct. This lets you pass any factory or
* product subclass to the client code without breaking it.
*/
namespace ClientCode {
void clientCode(IProductAbstractFactory* f) {
ICMakeProduct* cmake = f->createCMakeProduct();
IGdbProduct* gdb = f->createGdbProduct();
cmake->launch();
gdb->launch();

delete cmake;
delete gdb;
}
} // namespace ClientCode

// static redudant inside anonymous namespace
IProductAbstractFactory* createProductFactory(const std::string& os) {
if (os == "linux") {
return new LinuxProductFactory();
} else if (os == "windows") {
return new WindowsProductFactory();
} else if (os == "macos") {
return new MacOsProductFactory();
} else {
std::cout << "OS not support yet - " << os << "\n";
return nullptr;
}
}

void run() {
std::string os = "linux";
IProductAbstractFactory* factory = createProductFactory(os);
ClientCode::clientCode(factory);
delete factory;
}
} // namespace AbstractFactory
} // namespace

struct AbstractFactoryAutoRunner {
AbstractFactoryAutoRunner() {
std::cout << "\n--- AbstractFactory Pattern Example ---\n";
AbstractFactory::run();
}
};

static AbstractFactoryAutoRunner instance;
50 changes: 25 additions & 25 deletions src/patterns/creational/FactoryMethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,23 @@ class MacOsGdbProduct : public IGdbProduct {
}
};

// ===================================================================================

/**
* The Creator class declares the factory method that is supposed to return an
* object of a Product class. The Creator's subclasses usually provide the
* implementation of this method.
* implementation of this method. (a.k.a IGdbFactory)
*/
class IGdbCreator {
class IGdbFactory {
public:
virtual ~IGdbCreator() = default;
virtual ~IGdbFactory() = default;
virtual IGdbProduct* factoryMethod() = 0;
virtual void launchGdb() = 0;
};

class AbstractGdbCreater : public IGdbCreator {
class AbstractGdbFactory : public IGdbFactory {
public:
// Call the factory method to create a Product object.

// Call the factory method to create a Product object.
void launchGdb() override final {
IGdbProduct* gdb = this->factoryMethod();
gdb->launch();
Expand All @@ -78,52 +79,51 @@ class AbstractGdbCreater : public IGdbCreator {
* Concrete Creators override the factory method in order to change the
* resulting product's type.
*/
class WindowsGdbCreator : public AbstractGdbCreater {
class WindowsGdbFactory : public AbstractGdbFactory {
public:
IGdbProduct* factoryMethod() override { return new WindowsGdbProduct(); }
};

class LinuxGdbCreator : public AbstractGdbCreater {
class LinuxGdbFactory : public AbstractGdbFactory {
public:
IGdbProduct* factoryMethod() override { return new LinuxGdbProduct(); }
};

class MacOsGdbCreator : public AbstractGdbCreater {
class MacOsGdbFactory : public AbstractGdbFactory {
public:
IGdbProduct* factoryMethod() override { return new MacOsGdbProduct(); }
};

// ===================================================================================

/**
* The client code works with an instance of a concrete creator, albeit through
* its base interface. As long as the client keeps working with the creator via
* the base interface, you can pass it any creator's subclass.
*/
namespace ClientCode {
void clientCode(IGdbCreator* gdb) {
void clientCode(IGdbFactory* gdb) {
if (gdb != nullptr)
gdb->launchGdb();
}
} // namespace ClientCode

class GdbCreatorFactory {
public:
static IGdbCreator* createGdbCreator(const std::string& os) {
if (os == "linux") {
return new LinuxGdbCreator();
} else if (os == "windows") {
return new WindowsGdbCreator();
} else if (os == "macos") {
return new MacOsGdbCreator();
} else {
std::cout << "OS not support yet - " << os << "\n";
return nullptr;
}
IGdbFactory* createGdbFactory(const std::string& os) {
if (os == "linux") {
return new LinuxGdbFactory();
} else if (os == "windows") {
return new WindowsGdbFactory();
} else if (os == "macos") {
return new MacOsGdbFactory();
} else {
std::cout << "OS not support yet - " << os << "\n";
return nullptr;
}
};
}

void run() {
std::string os = "linux";
IGdbCreator* gdb = GdbCreatorFactory::createGdbCreator(os);
IGdbFactory* gdb = createGdbFactory(os);
ClientCode::clientCode(gdb);
delete gdb;
}
Expand Down
Loading