问题描述
当使用 CRTP 时,我试图根据一些配置值创建对象。 但是我不确定我在调用Factory create方法时在main方法中声明的类型应该是什么。
这是 CRTP 的基类
template <typename TConfigurationStore>
class ConfigManager
{
public:
ConfigManager() = default;
bool Configure(const INIReader& iniReader)
{
LOG(INFO) << "ConfigManager::Configure called.";
return static_cast<TConfigurationStore*>(this)->Configure(iniReader);
}
};
我们想要使用的实现。
class RedisConfiguration : public ConfigManager<RedisConfiguration>
{
public:
bool Configure(const INIReader& iniReader)
{
LOG(INFO) << "RedisConfiguration::Configure called";
return true;
}
};
另一个实现...
class FileConfiguration : public ConfigManager<FileConfiguration>
{
public:
bool Configure(const INIReader& iniReader)
{
LOG(INFO) << "EmptyConfiguration::Configure called";
return false;
}
};
class ConfigManagerFactory
{
public:
template <typename TConfigurationStore>
static ConfigManager<TConfigurationStore> *CreateConfigManager(const INIReader& iniReader)
{
std::string remoteConfigType = iniReader.Get("RemoteConfiguration","type","");
if (remoteConfigType == REdis_TYPE_NAME)
{
return new RedisConfiguration();
}
return new EmptyConfiguration();;
}
private:
inline static const std::string REdis_TYPE_NAME {"redis"};
};
我的问题是我应该用什么来代替 X
int main()
{
X myconfmgr = ConfigManagerFactory::CreateConfigManager(iniReader);
}
解决方法
如果没有 CreateConfigManager()
的调用者以与 iniReader
相同的方式分析 CreateConfigManager()
,它根本无法知道将哪个模板参数指定给 CreateConfigManager()
,例如:
std::string remoteConfigType = iniReader.Get("RemoteConfiguration","type","");
if (remoteConfigType == "redis")
{
auto myconfmgr = ConfigManagerFactory::CreateConfigManager<RedisConfiguration>(iniReader);
myconfmgr->Configure(iniReader);
...
delete myconfmgr;
}
else
{
...
}
调用者不必关心传入工厂的类型。这完全违背了使用工厂的初衷。
我同意@Human-Compiler 的评论。 CRTP 对于这段代码真的没有意义。简单的多态性就足够了。
去掉模板,使Configure()
和~ConfigManager()
在virtual
中成为ConfigManager
,在Configure()
中覆盖RedisConfiguration
,{{ 1}} 等。那么 FileConfiguration
可以返回一个普通的 CreateConfigManager()
(或者更好的 ConfigManager*
)。
试试这个:
std::unique_ptr<ConfigManager>
class ConfigManager
{
public:
ConfigManager() = default;
virtual ~ConfigManager() = default;
virtual bool Configure(const INIReader& iniReader) = 0;
};
class RedisConfiguration : public ConfigManager
{
public:
bool Configure(const INIReader& iniReader) override
{
LOG(INFO) << "RedisConfiguration::Configure called";
return true;
}
};
class FileConfiguration : public ConfigManager
{
public:
bool Configure(const INIReader& iniReader) override
{
LOG(INFO) << "EmptyConfiguration::Configure called";
return false;
}
};
class ConfigManagerFactory
{
public:
static std::unique_ptr<ConfigManager> CreateConfigManager(const INIReader& iniReader)
{
std::string remoteConfigType = iniReader.Get("RemoteConfiguration","");
if (remoteConfigType == REDIS_TYPE_NAME)
{
return std::make_unique<RedisConfiguration>();
}
...
return std::make_unique<EmptyConfiguration>();
}
private:
inline static const std::string REDIS_TYPE_NAME {"redis"};
};