I've implemented a factory pattern in C++ some weeks ago using the following guide : https://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus
Since then it worked well: all of the methods used in the factory pattern were returning the same type, and were also taking the same arguments types, until today. I now need to add bind new arguments to the methods I use, so methods signatures are not the same anymore.
I am currentyl using 2 things, and implementing a third one :
1) Actions: each represented as a class and containing a static AAction::ptr create(void* buff) method. Actions inherits from AAction class. Actions can be serialized using their own serialize() internal method, or deserialized using their create(buff) static method. The buffer argument contains the id and password necessary to call the LoginAction() constructor.
class AAction {
typedef std::unique_ptr<AAction> ptr;
};
class LoginAction : public AAction {
private:
std::string id;
std::string password;
bool authenticated;
public:
LoginAction(std::string id, std::string password);
virtual ~LoginAction() = default;
void execute();
static AAction::ptr create(const void* buffer);
};
2) ActionFactory: used to deserialize incoming actions, by calling the appropriate create() static method from the correct class.
class ActionFactory {
typedef std::unique_ptr<AAction> (*CreateActionFn)(const void*);
typedef std::map<RawActionType, CreateActionFn> RawFactoryMap;
RawFactoryMap rawFactoryMap;
public:
ActionFactory(Authenticator& authenticator) {
this->registerMethod(RawActionType_RawLoginAction, &LoginAction::create);
this->registerMethod(RawActionType_RawLogoutAction, &LogoutAction::create);
this->registerMethod(RawActionType_RawStandAction, &StandAction::create);
}
void registerMethod(const RawActionType &rawActionType, CreateActionFn pfnCreate);
std::unique_ptr<AAction> getAction(RawActionType rawActionType, const void* buffer);
};
Actions can be executed at any time in the code, by simply calling the execute() method, with no parameters.
Up to this point, eveything works fine. The issue is that I now need to add some more parameters to actions that are not stored inside the password. For example in my case: an Authenticator
3) An Authenticator, to authenticate a user.
So that inside LoginAction::execute(), all I have to do is call
this->authenticator.authenticate(this->id, this->password).
Here are the changes I made for that :
-
I added authenticator to the LoginAction constructor :
LoginAction(Authenticator& authenticator, std::string id, std::string password);
And a field :
Authenticator& authenticator;
-
I added authenticator to the LoginAction::create static method :
static AAction::ptr create(const void* buffer, Authenticator& authenticator);
-
I modified, inside the ActionFactory constructor, the way I register method, using std::bind :
this->registerMethod(RawActions_RawLoginAction, std::bind(&LoginAction::create, std::placeholders::_1, authenticator);
But, as my function types have changed, I cannot store it in the RawFactoryMap anymore.
error: invalid cast from type ‘std::_Bind_helper ()(const void, Authenticator&), const std::_Placeholder<1>&, Authenticator&>::type {aka std::_Bind ((std::_Placeholder<1>, Authenticator))(const void, Authenticator&)>}’ to type ‘ActionFactory::CreateActionFn {aka std::unique_ptr ()(const void)}’
What is the best way to proceed, to keep a map of functions in the ActionFactory and respect the Factory pattern ?
Thanks in advance, and have a good day!
As an additional note: I am open and would be glad to read any suggestion on how to improve my code, even for some minor improvements.
Aucun commentaire:
Enregistrer un commentaire