design pattern - factory pattern in c++ and lua

7.5k 词


Factory Pattern Wiki

In object-oriented programming (OOP), a factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class from some method call, which is assumed to be “new”. More broadly, a subroutine that returns a “new” object may be referred to as a “factory”, as in factory method or factory function. This is a basic concept in OOP, and forms the basis for a number of related software design patterns.


一一一一一一一一一一一一一一一一一一一一一一一一
© Hung-Chi's Blog
https://hungchicheng.github.io/2017/12/07/Design-Patterns-Factory-Pattern-in-lua-and-C++/
一一一一一一一一一一一一一一一一一一一一一一一一


What is Factory Pattern

Example in C++

#include <iostream>
#include <unordered_map>
#include <functional>
#include <vector>

// Base
class Monster {
public:
    virtual void appear() = 0;
};

// Factory
class MonsterFactory {
public:
typedef std::unordered_map<std::string, std::function<Monster*()>> registry_map;

<span class="c1">// use this to instantiate the proper Derived class

static Monster * instantiate(const std::string& name)
{
auto it = MonsterFactory::registry().find(name);
return it == MonsterFactory::registry().end() ? nullptr : (it->second)();
}

<span class="k">static</span> <span class="n">registry_map</span> <span class="o">&amp;</span> <span class="n">registry</span><span class="p">(){</span>
    <span class="k">static</span> <span class="n">registry_map</span> <span class="n">impl</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">impl</span><span class="p">;</span>
<span class="p">}</span>

};

template<typename T> struct MonsterFactoryRegister
{
MonsterFactoryRegister(std::string name)
{
MonsterFactory::registry()[name] = { return new T; };
std::cout << "Registering class '" << name << "'n";
}
};
//------------------

class Ogre : public Monster {
public:
void appear() { std::cout << "appearing an Ogre " <<std::endl; }
private:
static MonsterFactoryRegister<Ogre> AddToFactory_;
};

MonsterFactoryRegister<Ogre> Ogre::AddToFactory_("Ogre" );
//------------------

class Demon : public Monster {
public:
void appear() { std::cout << "appearing a Demon " <<std::endl; }
private:
static MonsterFactoryRegister<Demon> AddToFactory_;
};

MonsterFactoryRegister<Demon> Demon::AddToFactory_("Demon" );
//------------------

class Troll : public Monster {
public:
void appear() { std::cout << "appearing a Troll " <<std::endl; }
private:
static MonsterFactoryRegister<Troll> AddToFactory_;
};

MonsterFactoryRegister<Troll> Troll::AddToFactory_("Troll" );
//------------------

int main(int argc, char argv[])
{
std::vector<Monster
> Monsters;

<span class="n">Monsters</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span> <span class="n">MonsterFactory</span><span class="o">::</span><span class="n">instantiate</span><span class="p">(</span><span class="s">&#34;Ogre&#34;</span><span class="p">)</span> <span class="p">);</span>
<span class="n">Monsters</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span> <span class="n">MonsterFactory</span><span class="o">::</span><span class="n">instantiate</span><span class="p">(</span><span class="s">&#34;Demon&#34;</span><span class="p">)</span> <span class="p">);</span>
<span class="n">Monsters</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span> <span class="n">MonsterFactory</span><span class="o">::</span><span class="n">instantiate</span><span class="p">(</span><span class="s">&#34;Troll&#34;</span><span class="p">)</span> <span class="p">);</span>

<span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">Monster</span><span class="o">:</span> <span class="n">Monsters</span><span class="p">){</span>
    <span class="n">Monster</span><span class="o">-&gt;</span><span class="n">appear</span><span class="p">();</span>
<span class="p">}</span>

<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>

}

Output:

Registering class 'Ogre'
Registering class 'Demon'
Registering class 'Troll'
appearing an Ogre 
appearing a Demon 
appearing a Troll 
appearing a Troll 
Program ended with exit code: 0

Download - Source Code


Example in Lua

function FuncNew( obj ) -- for Inheritance 
    function obj:new( o )
        o = o or {}
        setmetatable( o, self )
        self.__index = self
        return o
    end
    return obj
end


Monster = {}
function Monster:create()
return FuncNew( Monster ):new()
end
function Monster:appear() – virtual
– do nothing
end


Ogre = Monster:create() – inheritance Monster
Ogre.name = "Ogre"
function Ogre:create()
return FuncNew( Ogre ):new()
end
function Ogre:appear() – override
print( "appearing an " Ogre.name )
end

Demon = Monster:create() – inheritance Monster
Demon.name = "Demon"
function Demon:create()
return FuncNew( Demon ):new()
end
function Demon:appear() – override
print( "appearing a " Demon.name )
end

Troll = Monster:create() – inheritance Monster
Troll.name = "Troll"
function Troll:create()
return FuncNew( Troll ):new()
end
function Troll:appear() – override
print( "appearing a " Troll.name )
end


MonsterFactory = {}
MonsterFactory.registryTable = {}
function MonsterFactory:create()
return MonsterFactory
end
function MonsterFactory:instantiate( name )
for k,v in pairs(self.registryTable) do
if v.name == name then
return v:create()
end
end
return nil
end
function MonsterFactory:registry( monster )
print( "Registering class '" monster.name "'" )
table.insert( self.registryTable, monster )
end


MonsterFactory:registry( Ogre )
MonsterFactory:registry( Demon )
MonsterFactory:registry( Troll )

------------------------------------------------------
local monsters = {}

table.insert( monsters, MonsterFactory:instantiate( "Ogre" ) )
table.insert( monsters, MonsterFactory:instantiate( "Demon" ) )
table.insert( monsters, MonsterFactory:instantiate( "Troll" ) )

for k,v in pairs(monsters) do
v:appear()
end

Output:

Registering class 'Ogre'
Registering class 'Demon'
Registering class 'Troll'
appearing an Ogre
appearing a Demon
appearing a Troll
[Finished in 0.0s]

Download - Source Code