Search code examples
c++design-patternsfactory-pattern

Passing value in factory pattern


I am learning factory design pattern. I am not able to figure out how we can pass parameters to object created using Factory pattern.

One Small Silly Example:

Suppose I have three class, Class A and class B and Class Number. Number being the base class. Also, class A expects three integers and has functionality to add them and class B expects two integer and adds them

Code Snippet:

int main()
{

    Factory *facObj = new Factory();
    // Addition for Two Integers
    Number * numberObjOne = facObj->createObj("AddThreeInteger");
    Number * numberObjTwo = facObj->createObj("AddTwoInteger");
}

Factory.cpp

Number * Factory::createObj(string str)
{
    if (str == "AddThreeInteger")
    {
        return new A(1,2,3);
    }
    else if (str == "AddTwoInteger")
    {
        return new B(1,2);
    }
    else            
        return NULL;
}

Question: Now no matter what I do I can only add the hard coded numbers. How do I pass these integers value from my Client code or from main(). Its a silly example and I am new to programming. Kindly help me here. How can I not hardcode the value and get the results. Can I somwhow pass the values at facObj->createObj Am I making sense? Kindly help me.


Solution

  • Complete, runnable example. c++11 or better.

    Note the use of unique_ptr. Don't use raw pointers.

    #include <iostream>
    #include <memory>
    #include <stdexcept>
    #include <exception>
    #include <utility>
    
    template<class T, class...Args>
    struct creatable_from {
        template<class X, class...Ys>
        static auto test(int) -> decltype(X(std::declval<Ys>()...), void(), std::true_type());
    
        template<class X, class...Ys>
        static auto test(...) -> decltype(std::false_type());
    
        static constexpr auto value = decltype(test<T, Args...>(0))::value;
    
    };
    
    struct Operation {
        virtual ~Operation() = default;
    
        virtual int operator()() const = 0;
    };
    
    struct Add : Operation
    {
        Add(int x, int y)
        : x(x), y(y)
        {}
    
        int operator()() const override {
            return x + y;
        }
    
        int x, y;
    };
    
    struct Sub : Operation
    {
        Sub(int x, int y)
        : x(x), y(y)
        {}
    
        int operator()() const override {
            return x - y;
        }
    
        int x, y;
    };
    
    struct AddSub : Operation
    {
        AddSub(int x, int y, int z)
        : x(x), y(y), z(z)
        {}
    
        int operator()() const override {
            return x + y - z;
        }
    
        int x, y, z;
    };
    
    struct Factory
    {
        template<class...Args>
        std::unique_ptr<Operation> create(const std::string& type, Args&&...args)
        {
            if (type == "Add") {
                return do_create<Add>(std::forward<Args>(args)...);
            }
            if (type == "Sub") {
                return do_create<Sub>(std::forward<Args>(args)...);
            }
            if (type == "AddSub") {
                return do_create<AddSub>(std::forward<Args>(args)...);
            }
    
            // default - return a null pointer, but would probably be better to
            // throw a logic_error
            return {};
        }
    
    private:
        template<class T, class...Args>
        static auto do_create(Args&&...args)
        -> std::enable_if_t< creatable_from<T, Args...>::value, std::unique_ptr<T> >
        {
            return std::make_unique<T>(std::forward<Args>(args)...);
        }
    
        template<class T, class...Args>
        static auto do_create(Args&&...args)
        -> std::enable_if_t< not creatable_from<T, Args...>::value, std::unique_ptr<T> >
        {
            throw std::invalid_argument("wrong number of arguments");
        }
    
    };
    
    int main()
    {
    
        auto facObj = Factory();
        auto t1 = facObj.create("Add", 2, 3);
        auto t2 = facObj.create("Sub", 3, 2);
        auto t3 = facObj.create("AddSub", 2, 3, 4);
    
        std::cout << (*t1)() << std::endl;
        std::cout << (*t2)() << std::endl;
        std::cout << (*t3)() << std::endl;
    }
    

    expected output:

    5
    1
    1