Reputation: 103
In the target of learning the OOP in C++, I want to create a ToolFactory with the factory design pattern.
But I don't know how I must develop this. But I had try to develop it, but it doesn't work.
You find below all the code I have made for create the ToolFactory and can to create a toolbox with a vector.
I hope to be clear in my question.
#ifndef BRICOLEUR_HPP
#define BRICOLEUR_HPP
#include <ScrewDriver.hpp>
#include <Saw.hpp>
#include <Hammer.hpp>
#include <string>
class Handyman
{
public:
void screw(ScrewDriver t){t.screw();}
void cut(Saw s){s.cut();}
void crack(Hammer m){m.crack();}
};
#endif
Hammer.hpp :
#ifndef MARTEAU_HPP
#define MARTEAU_HPP
#include <iostream>
#include <Tool.hpp>
#include <ToolBreak.hpp>
class Hammer : public Tool, ToolBreak
{
std::string nom;
public:
Hammer(std::string const & nom){this->nom = nom;}
std::string get_nom(){return this->nom;}
void crack(){std::cout << "Hammer crack" << std::endl;}
~Hammer();
};
#endif
Saw.hpp :
....
#include <ToolCutting.hpp>
class Saw : public Tool, ToolCutting
{
....
public:
....
void cut(){std::cout << "Saw cut" << std::endl;}
....
};
#endif
Screwdriver.hpp :
....
#include <ToolScrewing.hpp>
class ScrewDriver : public Tool, ToolScrewing
{
....
public:
....
void screw(){std::cout << "ScrewDriver screw" << std::endl;}
....
};
#endif
#ifndef TOOLBREAK_HPP
#define TOOLBREAK_HPP
#include <string>
class ToolBreak
{
public:
virtual std::string get_nom() = 0;
virtual void crack() = 0;
};
#endif
The same model for the interface :
#ifndef TOOLFACTORY_HPP
#define TOOLFACTORY_HPP
#include <memory>
#include <Tool.hpp>
#include <ScrewDriver.hpp>
#include <Hammer.hpp>
#include <Saw.hpp>
class ToolFactory
{
public:
static Tool create (std::string name, std::string arg);
};
#endif
ToolFactory.cpp
#include <ToolFactory.hpp>
Tool ToolFactory::create(std::string name, std::string args)
{
if(name.compare("Screwdriver") == 0)
{
return ScrewDriver(args);
}
else if(name.compare("Hammer") == 0)
{
return Hammer(args);
}
else if(name.compare("Saw") == 0)
{
return Saw(args);
}
else
{
std::cout << "Error ! Tool not found" << std::endl;
}
}
#include <vector>
#include <Handyman.hpp>
#include <ToolFactory.hpp>
using namespace std;
int main()
{
Handyman handy;
ScrewDriver screwdriver("Blue screwdriver");
Saw saw("Green saw");
Hammer hammer("Yellow hammer");
handy.screw(screwdriver);
handy.cut(saw);
handy.crack(hammer);
Tool screwdriverV2 = ToolFactory::create("Screwdriver", "Screwdriver v2");
screwdriverV2.display();
return 0;
}
clang++ -Wall -std=c++14 -c -o obj/main.o src/main.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/Handyman.o src/Handyman.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/Saw.o src/Saw.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/ScrewDriver.o src/ScrewDriver.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/Hammer.o src/Hammer.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/Tool.o src/Tool.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/ToolScrewing.o src/ToolScrewing.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/ToolBreak.o src/ToolBreak.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/ToolCutting.o src/ToolCutting.cpp -I include
clang++ -Wall -std=c++14 -c -o obj/ToolFactory.o src/ToolFactory.cpp -I include
src/ToolFactory.cpp:21:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
1 warning generated.
clang++ -Wall -std=c++14 -o bin/main obj/main.o obj/Handyman.o obj/Saw.o obj/ScrewDriver.o obj/Hammer.o obj/Tool.o obj/ToolScrewing.o obj/ToolBreak.o obj/ToolCutting.o obj/ToolFactory.o
./bin/main
ScrewDriver screw
Saw cut
Hammer crack
It's a tool
Upvotes: 1
Views: 558
Reputation: 44288
To keep object type you need to pass it by pointer, not value, otherwise you will have problem with object slicing. As you pass object ownership when you create, you should use smart pointer:
class ToolFactory
{
public:
static std::unique_ptr<Tool> create (std::string name, std::string arg);
};
std::unique_ptr<Tool> ToolFactory::create(std::string name, std::string args)
{
if(name.compare("Screwdriver") == 0)
{
return std::make_unique<ScrewDriver>(args);
}
// note as your if has return statement you do not really need else
...
}
Next step could be to eliminate cascade if
with std::unordered_map
:
class ToolFactory
{
using Creator = std::function<std::unique_ptr<Tool>(std::string)>
using Creators = std::unordered_map<std::string,Creator>;
Creators m_creators;
public:
ToolFactory();
std::unique_ptr<Tool> create (std::string name, std::string arg);
};
ToolFactory::ToolFactory()
{
m_creators[ "Screwdriver" ] = []( std::string arg ) { return std::make_unique<ScrewDriver>(arg); }
...
}
std::unique_ptr<Tool> ToolFactory::create (std::string name, std::string arg)
{
auto f = m_creators.find( name );
if( f == m_creators.end() )
throw std::runtime_error( "unknown type:" + name );
return f->second( arg );
}
This way it would be not only more generic but you can easily extend it to add new types dynamically.
Upvotes: 3