Reputation: 427
I am writing an application that can launch new process'. I have identified that these process' will fundamentally differ in two ways, either they can run standalone or depend on an existing process to function. So I therefore have created two abstract classes, inheriting from a base abstract class.
I am trying to work out how to write a factory or other design pattern that will return the class I need depending on a file extension string I give, which will happen at runtime. However I don't think that the factory pattern is a good,sensible fit as these fundamental difference results in differing constructors. I could write myself a huge switch or nested if statement that would work, but for this project I am really trying to increase my c++ knowledge (this is the first time I have used inheritance really).
Say I have my abstract base class :
class launchable {
protected:
std::string name;
std::string directory;
std::string path;
std::string fileType;
std::vector<std::string> launchArgs;
bool hasLaunched;
launchable(std::string _name, std::string _directory,std::string _fileType,std::vector<std::string> _args);
public:
virtual void start() = 0;
virtual void stop() = 0;
virtual void writeMessage(std::string theMessage) = 0;
virtual boost::optional<std::string> readMessage() = 0;
};
and then two further abstract classes inheriting from this, firstly a standalone class that starts/stops and writes to its own process:
class standalone : public launchable{
protected:
processManager *manager;
std::shared_ptr<processManager::launchableProcess> process;
virtual std::string formatWriteMessage(std::string theMessage) = 0;
standalone(std::string _name, std::string _directory,std::string _fileType,std::vector<std::string> _args,processManager *_manager);
public:
virtual void start() = 0;
virtual void stop() = 0;
void writeMessage(std::string theMessage);
boost::optional<std::string> readMessage();
};
and a dependent class that must start/stop/read/write through a standalone process:
class dependent : public launchable{
protected:
standalone *dependency;
dependent(std::string _name, std::string _directory,std::string _type,std::vector<std::string> _args,standalone *_dependency);
public:
virtual void start() = 0;
virtual void stop() = 0;
void writeMessage(std::string theMessage);
boost::optional<std::string> readMessage();
};
An example concrete standalone, *nix executable that runs on a command line:
class executable : public standalone {
private:
std::string formatWriteMessage(std::string theMessage);
public:
using standalone::standalone;
void start();
void stop();
};
And example concrete dependable, a supercollider patch that must run through a *nix command line interpreter:
class supercolliderPatch : public dependent {
public:
using dependent::dependent;
void start();
void stop();
};
So ideally what I would want is something like (pseudocode):
launchable *sclang = launchableFactory.create("exec",ARGS); // returns a standalone
launchable *patch = launchableFactory.create("supercolliderPatch",sclang,ARGS) // returns a dependable, with dependency set to sclang
And these launchable *instance would be stored within a std::vector.
Essentially my question is: am I on a fools errand trying to lump these two concepts of standalone/dependent into one or can the factory pattern work for me?
Upvotes: 2
Views: 4603
Reputation: 1789
You can try this, some of the functional programming, but it may have some minimal performance negative impact. Also it requires C++11 or later
std::function<shared_ptr<Base>()> funcs[] = { [](){ return shared_ptr<Base>(new A()); }, [](){ return shared_ptr<Base>(new B()); } };
Then call:
funcs[i]();
You can for safety, use something like array
.
std::array<std::function<shared_ptr<Base>()>, 2> funcs[] =
{ [](){ return shared_ptr<Base>(new A()); }, [](){ return shared_ptr<Base>(new B()); } };
(funcs->at(i)();
This "array of functions" are something like Abstract Factory that returns a shared pointer of the base class.
Upvotes: 1
Reputation: 46
Abstract Factory let's you do exactly that: Construct some concrete instance and treat it as it's abstract interface. If you can't find a common interface to work with both classes then you might want to reconsider your design, tho it doesn't seem like that's a problem in your case.
Upvotes: 2