From baabfa439a4a4c7a91d66917dae7df4786985a14 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Tue, 11 May 2021 15:42:08 -0400 Subject: [PATCH] Add abstract-factory pattern example --- cpp/patterns/abstract-factory/CMakeLists.txt | 21 +++++++ .../abstract-factory/abstract-factory.hpp | 60 +++++++++++++++++++ cpp/patterns/abstract-factory/factory.cpp | 55 +++++++++++++++++ cpp/patterns/abstract-factory/main.cpp | 35 +++++++++++ cpp/patterns/abstract-factory/parts.cpp | 19 ++++++ cpp/patterns/abstract-factory/parts.hpp | 35 +++++++++++ 6 files changed, 225 insertions(+) create mode 100644 cpp/patterns/abstract-factory/CMakeLists.txt create mode 100644 cpp/patterns/abstract-factory/abstract-factory.hpp create mode 100644 cpp/patterns/abstract-factory/factory.cpp create mode 100644 cpp/patterns/abstract-factory/main.cpp create mode 100644 cpp/patterns/abstract-factory/parts.cpp create mode 100644 cpp/patterns/abstract-factory/parts.hpp diff --git a/cpp/patterns/abstract-factory/CMakeLists.txt b/cpp/patterns/abstract-factory/CMakeLists.txt new file mode 100644 index 0000000..c0afde3 --- /dev/null +++ b/cpp/patterns/abstract-factory/CMakeLists.txt @@ -0,0 +1,21 @@ +############################################################################### +## Author: Shaun Reed ## +## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ## +## About: A project for practicing the abstract factory C++ design pattern ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +############################################################################## +# +cmake_minimum_required(VERSION 3.15) +project( + #[[NAME]] AbstractFactory + VERSION 1.0 + DESCRIPTION "An example of the abstract factory design pattern in C++" + LANGUAGES CXX +) +add_compile_options("-Wall") + +add_library(parts "parts.cpp") +add_library(abstract-factory "factory.cpp") +add_executable(abstract-factory-test "main.cpp") +target_link_libraries(abstract-factory-test abstract-factory parts) diff --git a/cpp/patterns/abstract-factory/abstract-factory.hpp b/cpp/patterns/abstract-factory/abstract-factory.hpp new file mode 100644 index 0000000..86939e5 --- /dev/null +++ b/cpp/patterns/abstract-factory/abstract-factory.hpp @@ -0,0 +1,60 @@ + +#ifndef FACTORY_HPP +#define FACTORY_HPP + +#include +#include +#include +#include +#include + +#include "parts.hpp" + +class AbstractFactory { +public: + AbstractFactory(std::string name_): name(std::move(name_)) {} + virtual ~AbstractFactory() = default; + + Part* requestPart(); + Part* requestPart(std::string partName, float price); + void showStock() const; + std::string getName() const { return name;} + +protected: + virtual Part* makePart() = 0; + virtual Part* makePart(std::string name, float price) = 0; + +private: + std::string name; + std::unordered_map inventory; +}; + + +/*****************************************************************************/ +// Gear Concrete Factory + +class GearFactory : public AbstractFactory { +public: + explicit GearFactory(std::string name_="GearFactory") : + AbstractFactory(std::move(name_)) {} + +protected: + Part* makePart() override; + Part* makePart(std::string name, float price); +}; + + +/*****************************************************************************/ +// Spring Concrete Factory + +class SpringFactory : public AbstractFactory { +public: + explicit SpringFactory (std::string name_="SpringFactory"): + AbstractFactory(std::move(name_)) {} + +protected: + Part* makePart() override; + Part* makePart(std::string name, float price); +}; + +#endif // FACTORY_HPP diff --git a/cpp/patterns/abstract-factory/factory.cpp b/cpp/patterns/abstract-factory/factory.cpp new file mode 100644 index 0000000..d493966 --- /dev/null +++ b/cpp/patterns/abstract-factory/factory.cpp @@ -0,0 +1,55 @@ + +#include + +#include "abstract-factory.hpp" + +Part* AbstractFactory::requestPart() { + // Create a new part + Part * newPart = makePart(); + // Increment the QTY for part in AbstractFactory::inventory base class + // + If the item is not in the inventory map, this will also add it first. + inventory[newPart->getName()]++; + // Make the requested part + return newPart; +} + +Part* AbstractFactory::requestPart(std::string partName, float price) +{ + Part * newPart = makePart(partName, price); + inventory[newPart->getName()]++; + return newPart; +} + +void AbstractFactory::showStock() const +{ + for (const auto &item : inventory) { + if (item.first.empty()) continue; // Don't show an empty item + std::cout << item.first << " QTY in stock: " << item.second << std::endl; + } +} + + +/*****************************************************************************/ +// Gear + +Part* GearFactory::makePart() { + return new Gear(); +} + +Part* GearFactory::makePart(std::string name, float price) +{ + return new Gear(name, price); +} + + +/*****************************************************************************/ +// Spring + +Part* SpringFactory::makePart() { + return new Spring(); +} + +Part *SpringFactory::makePart(std::string name, float price) +{ + return new Spring(name, price); +} diff --git a/cpp/patterns/abstract-factory/main.cpp b/cpp/patterns/abstract-factory/main.cpp new file mode 100644 index 0000000..71f9280 --- /dev/null +++ b/cpp/patterns/abstract-factory/main.cpp @@ -0,0 +1,35 @@ + +#include +#include +#include +#include + +#include "abstract-factory.hpp" + +int main(const int argc, const char * argv[]) { + // Testing GearFactory + GearFactory gearFactory; + const int gearsRequired = 5; + + std::cout << "Testing " << gearFactory.getName() <<"...\nMaking 5 Gears...\n"; + for (int i = 0; i < gearsRequired; i++) gearFactory.requestPart(); + std::cout << std::endl << gearFactory.getName() << " inventory:\n"; + gearFactory.showStock(); + + // Testing SpringFactory + SpringFactory springFactory; + const int springsRequired = 5; + for (int i = 0; i < springsRequired; i++) springFactory.requestPart(); + std::cout << std::endl << springFactory.getName() << " inventory:\n"; + springFactory.showStock(); + + + // Making custom gears and springs + for (int i = 0; i < gearsRequired; i++) gearFactory.requestPart("Big Gear", 2.5f); + std::cout << std::endl << gearFactory.getName() << " inventory:\n"; + gearFactory.showStock(); + + for (int i = 0; i < springsRequired; i++) springFactory.requestPart("Big Spring", 5.0f); + std::cout << std::endl << springFactory.getName() << " inventory:\n"; + springFactory.showStock(); +} diff --git a/cpp/patterns/abstract-factory/parts.cpp b/cpp/patterns/abstract-factory/parts.cpp new file mode 100644 index 0000000..01f1a5d --- /dev/null +++ b/cpp/patterns/abstract-factory/parts.cpp @@ -0,0 +1,19 @@ + +#include "parts.hpp" + +/*****************************************************************************/ +// Gear + +Gear::Gear(std::string name, float price) { + partName = name; + partPrice = price; +} + + +/*****************************************************************************/ +// Spring + +Spring::Spring(std::string name, float price) { + partName = name; + partPrice = price; +} diff --git a/cpp/patterns/abstract-factory/parts.hpp b/cpp/patterns/abstract-factory/parts.hpp new file mode 100644 index 0000000..acf0e74 --- /dev/null +++ b/cpp/patterns/abstract-factory/parts.hpp @@ -0,0 +1,35 @@ + +#ifndef PARTS_HPP +#define PARTS_HPP + +#include + +class Part { +public: + std::string getName() const { return partName;} + float getPrice() const { return partPrice;} + +protected: + std::string partName; // The name of the part + float partPrice; // The partPrice of the part +}; + + +/*****************************************************************************/ +// Gear + +class Gear : public Part { +public: + Gear(std::string name="Gear", float price = 1.0f); +}; + + +/*****************************************************************************/ +// Spring + +class Spring : public Part { +public: + Spring(std::string name = "Spring", float price = 2.0f); +}; + +#endif // PARTS_HPP