当与同一lib链接的不同样本需要不同的Imph时,如何桥接编译时间配置和工厂模式?
我向其他人提供一个类型擦除接口,如下所示:
class Interface{
public:
virtual int doSomething() = 0;
}
template <typename Repository>
class InterfaceImpl {
public:
int doSomething() override {
return repository_->doOtherThing();
}
private:
std::unique_ptr<Repository> repository_;
};
以及一个向调用者隐藏这些类型内容的工厂类。
std::unique_ptr<Interface> factory(int type){
switch(type){
case 1: return std::make_unique<InterfaceImpl<SQLiteRepository>>();
case 2: return std::make_unique<InterfaceImpl<DummyRepository>>();
// omitted ...
}
}
type
实际上是从配置文件中读取的东西,实际上是一个字符串什么的,我只是使用 int
来简化这里的代码。
直到昨天一切都正常。我的老板告诉我:“嘿菜鸟,你需要将 Repository
配置阶段从运行时提升到编译时。你不应该编译运行时不会使用的 RepositoryImpl
,因为这个决定可以在编译时确定,并且在整个应用程序的生命周期中不会改变,我们的 CI 管道的编译时间足够慢,所以请不要在其中添加更多的内容”。
为了维护当前向用户公开的 API,我想到的一个自然解决方案是将 switch
条件更改为一些 #ifdef
指令,并在 cmake 中添加一些相应的定义文件,例如:
std::unique_ptr<Interface> factory(){
#ifdef USE_SQLITE
return std::make_unique<InterfaceImpl<SQLiteRepository>>();
#elif defined(USE_DUMMY)
return std::make_unique<InterfaceImpl<DummyRepository>>();
// omitted ...
}
现在出现了棘手的问题:我们的项目 CMakeLists 包含许多示例和示例。测试,如下所示:
- project
- CMakeLists.txt
- include
- project
- lib.hpp
- src
- CMakeLists.txt
- lib.cpp
- samples
- CMakeLists.txt
- sampleA
- CMakeLists.txt
- main.cpp
- sampleB
- CMakeLists.txt
- main.cpp
- tests
- CMakeLists.txt
- testlib.cpp
其中一些需要不同的Repository
,例如,sampleA 可能使用SQLite
,而sampleB 使用Dummy
。这些示例需要链接 src/* 生成的 lib。是否应该编译这些不同的示例可以通过一些 cmake 选项来控制。
这使得工厂很难采用,因为我无法通过此函数同时返回 RepositoryA 和 RepositoryB 。
一种可能的解决方案是直接将InterfaceImpl暴露给API使用方,因此可以采用#ifdef的东西。然而,直接暴露这些是我们最初不希望看到的。
真诚感谢任何建议。
I am providing a type erased interface to others, which goes like:
class Interface{
public:
virtual int doSomething() = 0;
}
template <typename Repository>
class InterfaceImpl {
public:
int doSomething() override {
return repository_->doOtherThing();
}
private:
std::unique_ptr<Repository> repository_;
};
And a factory class that hide these type stuff from caller.
std::unique_ptr<Interface> factory(int type){
switch(type){
case 1: return std::make_unique<InterfaceImpl<SQLiteRepository>>();
case 2: return std::make_unique<InterfaceImpl<DummyRepository>>();
// omitted ...
}
}
The type
is actually something that read from configuration file, and is actually a string or something, i just use int
to simplify the code here.
Everything works fine until yesterday. My boss told me: "Hey rookie, you need to hoist the Repository
configuration stage from runtime to compile time. You should not compile the RepositoryImpl
that will not used at runtime, since the decision can be determined at compile time and will not change in the whole application's lifecycle. Our CI pipeline's compile time is slow enough, please don't append more shit to it".
To maintain the current API that exposed to user, a natural solution that comes to my mind is change the switch
conditions to some #ifdef
directives and add some corresponding definitions in the cmake file, like:
std::unique_ptr<Interface> factory(){
#ifdef USE_SQLITE
return std::make_unique<InterfaceImpl<SQLiteRepository>>();
#elif defined(USE_DUMMY)
return std::make_unique<InterfaceImpl<DummyRepository>>();
// omitted ...
}
Now the tricky issue occurs: Our projects CMakeLists contains many examples & tests, like below:
- project
- CMakeLists.txt
- include
- project
- lib.hpp
- src
- CMakeLists.txt
- lib.cpp
- samples
- CMakeLists.txt
- sampleA
- CMakeLists.txt
- main.cpp
- sampleB
- CMakeLists.txt
- main.cpp
- tests
- CMakeLists.txt
- testlib.cpp
Some of them needs different Repository
, for example, the sampleA might use SQLite
while sampleB using the Dummy
. These samples needs to link the lib that generated by src/*. And whether these different sample should be compiled can be controlled by some cmake options.
That makes the factory
thing hard to adopt, since i cannot both return RepositoryA
and RepositoryB
through this functions.
one possible solution is to directly expose the InterfaceImpl
to the API use side, so the #ifdef
stuffs can be adopted. However, directly expose these is the thing that we don't want initially.
Any advices is sincerely appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论