工厂模式和std :: bind方法

时间:2019-01-08 13:24:34

标签: c++ design-patterns bind c++17 factory

几周前,我已经使用以下指南在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模式的最佳方法是什么?

提前感谢,祝你有美好的一天!

作为补充说明:我很开放,很高兴阅读关于如何改进我的代码的任何建议,即使有一些小的改进。

1 个答案:

答案 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); }

它可能不会更短,但是更容易阅读。