我们有一个发布抽象基类的库:
(说明性伪代码)
/include/reader_api.hpp
class ReaderApi
{
public:
static std::unique_ptr <ReaderApi> CreatePcapReader ();
virtual ~ReaderApi() = 0;
};
在库实现中,有一个ReaderApi
读取 pcap 文件的具体实现:
/lib/pcap_reader_api.cpp
class PcapReaderApi
:
public ReaderApi
{
public:
ReaderApi() {};
};
客户端代码应PcapReaderApi
通过工厂方法实例化这些对象之一:
std::unique_ptr <ReaderApi> reader = ReaderApi::CreatePcapReader ();
这在几个层面上让我感觉很恶心。
首先,工厂方法应该是免费的,而static
不是ReaderApi
. 它是明确命名空间的static
成员。ReaderApi
无论哪种方式,我都可以看到利弊。随意对此发表评论,但这不是我的主要争论点。
其次,我的直觉告诉我我应该使用std::make_unique
而不是调用工厂方法。但由于创建的实际对象是一个实现细节,而不是公共标头的一部分,因此客户端无需make_unique
.
就可理解性和代码维护而言,最简单的解决方案似乎是我上面已经提出的解决方案,除非有更好的解决方案我还不知道。性能在这里不是主要考虑因素,因为由于此对象的性质,它只会在启动时实例化一次。
考虑到代码的清晰性、可理解性和可维护性,有没有比我这里更好的方法来设计这些对象的创建?
我已经考虑了两个替代方案,我将在下面讨论。
我考虑过的一种替代方法是将某种标识符传递给通用Create
函数。标识符将指定客户希望构建的对象类型。它可能是一个enum class
,沿着这些方向:
enum class DeviceType
{
PcapReader
};
std::unique_ptr <ReaderApi> CreateReaderDevice (DeviceType);
但我不确定我是否看到了这样做的意义,而不是仅仅让 create 函数变得自由和明确:
std::unique_ptr <ReaderApi> CreatePcapReader ();
我还考虑过在的构造函数中指定DeviceType
参数:ReaderApi
class ReaderApi
{
public:
ReaderApi (DeviceType type);
virtual ~ReaderApi() = 0;
};
这将启用make_unique
成语:
std::unique_ptr <ReaderApi> reader = std::make_unique <ReaderApi> (DeviceType::PcapReader);
但这显然会带来一个大问题——你实际上是在尝试构建 a ReaderApi
,而不是 a PcapReader
。解决这个问题的明显方法是实现一个virtual constructor
成语或使用工厂构造。但是对于我来说,虚拟构造似乎过度设计用于此用途。