У нас есть библиотека, которая публикует абстрактный базовый класс:
(иллюстративный псевдокод)
/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);
Но это, очевидно, представляет большую проблему — вы на самом деле пытаетесь построить ReaderApi
не PcapReader
, Очевидное решение этой проблемы заключается в реализации virtual constructor
идиома или использование фабричного строительства. Но виртуальная конструкция кажется мне слишком сложной для такого использования.
Для меня, два варианта, которые нужно рассмотреть, это ваш текущий подход или уровень пространства имен с подходящим названием free function. Кажется, нет нужды в перечисленной фабрике, если нет подробностей, о которых вы не упомянули.
С помощью make_unique
раскрывает детали реализации, поэтому я бы определенно не предлагал такой подход.