Created
October 7, 2017 17:36
-
-
Save PiJoules/228ea0a809511325ef298c09a1b24d64 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <initializer_list> | |
#include <iostream> | |
#include <memory> | |
#include <string> | |
// Example base type | |
class Base | |
{ | |
public: | |
Base(const double a, const double b) : | |
_a(a), | |
_b(b) | |
{ | |
} | |
virtual ~Base() {} | |
void print_ab() const | |
{ | |
std::cout << "a: " << _a << std::endl << "b: " << _b << std::endl; | |
} | |
protected: | |
double _a; | |
double _b; | |
}; | |
// Example type inheriting from Base | |
// For the factory create function to work, the static constant "name" is required | |
class Derived_1 : public Base | |
{ | |
public: | |
Derived_1(const double a, const double b) : | |
Base(a + 1, b + 1) | |
{ | |
} | |
~Derived_1() {} | |
static const std::string name; | |
}; | |
// Example type inheriting from Base | |
// For the factory create function to work, the static constant "name" is required | |
class Derived_2 : public Base | |
{ | |
public: | |
Derived_2(const double a, const double b) : | |
Base(a + 2, b + 2) | |
{ | |
} | |
~Derived_2() {} | |
static const std::string name; | |
}; | |
class Base2 | |
{ | |
public: | |
Base2(const std::string& a, const std::string& b) : | |
_a(a), | |
_b(b) | |
{ | |
} | |
virtual ~Base2() {} | |
void print_ab() const | |
{ | |
std::cout << "a: " << _a << std::endl << "b: " << _b << std::endl; | |
} | |
protected: | |
std::string _a; | |
std::string _b; | |
}; | |
// Example type inheriting from Base | |
// For the factory create function to work, the static constant "name" is required | |
class Derived_1_2 : public Base2 | |
{ | |
public: | |
Derived_1_2(const std::string& a, const std::string& b) : | |
Base2(a + "1", b + "1") | |
{ | |
} | |
~Derived_1_2() {} | |
static const std::string name; | |
}; | |
// Example type inheriting from Base | |
// For the factory create function to work, the static constant "name" is required | |
class Derived_2_2 : public Base2 | |
{ | |
public: | |
Derived_2_2(const std::string& a, const std::string& b) : | |
Base2(a + "2", b + "2") | |
{ | |
} | |
~Derived_2_2() {} | |
static const std::string name; | |
}; | |
// Forward declare template Abstract_factory type so it can be a template of itself | |
// Concreate factories can call Abstract_factory::create with their own type, the type of object they create, and any | |
// subclasses that they want to be able to create as template parameters. | |
template <class Factory_type, class Created_type, typename... Sub_classes> | |
class Abstract_factory; | |
// Template instance that unpacks one Sub_class type from Subclasses | |
// create will check if type is equal to the static member, "name" from Sub_class | |
template <class Factory_type, class Created_type, class Sub_class, typename... Sub_classes> | |
class Abstract_factory<Factory_type, Created_type, Sub_class, Sub_classes...> | |
{ | |
public: | |
template <typename... Args> | |
static std::unique_ptr<Created_type> create(const std::string& type, Args... args) | |
{ | |
if (type == Sub_class::name) | |
{ | |
// Found a valid type, call its constructor | |
std::cout << "Created object of type: " << Sub_class::name << std::endl; | |
// c++14: return std::move(std::make_unique<Sub_class>(a, b)); | |
return std::move(std::unique_ptr<Created_type>(new Sub_class(args...))); | |
} | |
// Check next subclass | |
return std::move(Abstract_factory<Factory_type, Created_type, Sub_classes...>::create(type, args...)); | |
} | |
}; | |
// Base case for recursive template of Abstract_factory. This will be reached if type could not be matched to one of the | |
// the subclasses specified in the original variadic template | |
template <class Factory_type, class Created_type> | |
class Abstract_factory<Factory_type, Created_type> | |
{ | |
public: | |
template <typename... Args> | |
static std::unique_ptr<Created_type> create(const std::string& type, Args... args) | |
{ | |
std::cout << "Invalid type: " << type << std::endl; | |
return nullptr; | |
} | |
}; | |
// Concreate instance of an Abstract_factory. It can just call Abstract_factory::create with the appropriate template | |
// parameters instead of having to write its own chain of if statements | |
class Base_factory | |
{ | |
public: | |
static std::unique_ptr<Base> create(const std::string& type, const double a, const double b) | |
{ | |
return std::move(Abstract_factory<Base_factory, Base, Derived_1, Derived_2>::create(type, a, b)); | |
} | |
}; | |
class Base_factory2 | |
{ | |
public: | |
static std::unique_ptr<Base2> create(const std::string& type, const std::string& a, const std::string& b) | |
{ | |
return std::move(Abstract_factory<Base_factory2, Base2, Derived_1_2, Derived_2_2>::create(type, a, b)); | |
} | |
}; | |
// Declare the concrete type identifiers. | |
const std::string Derived_1::name = "D1"; | |
const std::string Derived_2::name = "D2"; | |
const std::string Derived_1_2::name = "D1_2"; | |
const std::string Derived_2_2::name = "D2_2"; | |
// | |
void check_and_print_Base_info(std::string name) | |
{ | |
std::cout << "Attempting to create object of type " << name << std::endl; | |
auto d = Base_factory::create(name, 0, 0); | |
if (d != nullptr) | |
{ | |
d->print_ab(); | |
} | |
} | |
void check_and_print_Base2_info(std::string name) | |
{ | |
std::cout << "Attempting to create object of type " << name << std::endl; | |
auto d = Base_factory2::create(name, "ayy", "lmao"); | |
if (d != nullptr) | |
{ | |
d->print_ab(); | |
} | |
} | |
// Compile with: g++ test_abstract_factory -o test -std=c++11 | |
// Usage: ./test_abstract_factory [type1, type2, ...] | |
int main(int argc, char* argv[]) | |
{ | |
// If arguments are provided, attempt to create a Base pointer from arguments. | |
if (argc > 1) | |
{ | |
for (size_t i = 1; i < argc; ++i) | |
{ | |
check_and_print_Base_info(argv[i]); | |
} | |
} | |
// Otherwise create each example subclass and attempt to create from invalid type | |
else | |
{ | |
check_and_print_Base_info("D1"); | |
check_and_print_Base_info("D2"); | |
check_and_print_Base_info(""); | |
check_and_print_Base2_info("D1_2"); | |
check_and_print_Base2_info("D2_2"); | |
check_and_print_Base2_info(""); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment