几周前,我已经使用以下指南在C ++中实现了工厂模式:https://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus
从那时起,它一直运行良好:直到今天,工厂模式中使用的所有方法都返回相同的类型,并且也采用相同的参数类型。现在,我需要在我使用的方法上添加绑定新参数,因此方法签名不再相同。
我是currentyl,使用了两件事,并实现了第三件事:
1)动作:每个动作都表示为一个类,并包含一个静态AAction :: ptr create(void * buff)方法。动作继承自AAction类。动作可以使用自己的serialize()内部方法进行序列化,也可以使用其create(buff)静态方法进行反序列化。 buffer参数包含调用LoginAction()构造函数所需的ID和密码。
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:用于反序列化传入的操作,方法是从正确的类中调用适当的create()静态方法。
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);
};
可以在代码中的任何时间通过简单地调用无参数的execute()方法来执行动作。
到目前为止,一切正常。 问题是我现在需要向未存储在密码中的操作添加更多参数。例如,在我的情况下:身份验证器
3)身份验证器,用于验证用户。
因此在LoginAction :: execute()中,我要做的就是调用
this->authenticator.authenticate(this->id, this->password).
这是我为此所做的更改:
我将身份验证器添加到LoginAction构造函数中:
LoginAction(Authenticator& authenticator, std::string id, std::string password);
和一个字段:
Authenticator& authenticator;
我将身份验证器添加到LoginAction :: create静态方法中:
static AAction::ptr create(const void* buffer, Authenticator& authenticator);
我使用std :: bind在ActionFactory构造函数中修改了我注册方法的方式:
this->registerMethod(RawActions_RawLoginAction, std::bind(&LoginAction::create, std::placeholders::_1, authenticator);
但是,由于我的函数类型已更改,因此我无法再将其存储在RawFactoryMap中。
错误:类型)(const void ,Authenticator&),const无效 std :: _ Placeholder <1>&,Authenticator&> :: type {aka std :: _ Bind((std :: __ Placeholder <1>, Authenticator))(const void ,Authenticator&)>}'进行输入 ‘ActionFactory :: CreateActionFn {aka std :: unique_ptr()(const 无效)}’
在ActionFactory中保留功能图并尊重Factory模式的最佳方法是什么?
提前感谢,祝你有美好的一天!
作为补充说明:我很开放,很高兴阅读关于如何改进我的代码的任何建议,即使有一些小的改进。
答案 0 :(得分:3)
第一件事。使用C ++ 11,强烈建议using
胜过typedef
。考虑以下内容之间可读性的差异:
typedef std::unique_ptr<AAction> (*CreateActionFn)(const void*);
typedef std::map<RawActionType, CreateActionFn> RawFactoryMap;
和:
using CreateActionFn = std::unique_ptr<AAction>(*)(const void*);
using RawFactoryMap = std::map<RawActionType, CreateActionFn>;
当名称出现在左侧而不是任意位置时,这很好。
也就是说,现在函数指针已经不足,因为您需要存储状态,因此需要归纳为任意可调用对象。这就是std::function
的用途:提供的签名的类型擦除的可调用项:
using CreateActionFn = std::function<std::unique_ptr<AAction>(const void*)>;
这将匹配任何可复制且您可以使用const void*
调用并获得unique_ptr<AAction>
的可调用对象。
当我们在这里时,请勿使用std::bind
:
std::bind(&LoginAction::create, std::placeholders::_1, authenticator)
使用lambda:
[authenticator](void const* ptr){ return LoginAction::create(ptr, authenticator); }
或:
[=](void const* ptr){ return LoginAction::create(ptr, authenticator); }
它可能不会更短,但是更容易阅读。