Хотите знать, может ли кто-нибудь помочь определить более элегантный подход к дизайну - или, возможно, определить недостатки следующего дизайна.
В настоящее время у меня есть абстрактный класс Response
, производный от сериализуемого JSON Object
.
//objects.h
struct Object
{
[[nodiscard]] std::string serialize() const;
virtual void deserialize(const Poco::JSON::Object::Ptr &payload) = 0;
[[nodiscard]] virtual Poco::JSON::Object::Ptr to_json() const = 0;
};
// response.h
class Response : public Object
{
public:
std::unique_ptr<Data> data;
std::unique_ptr<Links> links;
};
Где переменные-члены Data
и Links
являются абстрактными базовыми классами, в которых их соответствующий набор подклассов содержит различные контейнеры STL.
Теперь проблема, с которой я сталкиваюсь, связана с дизайном класса и как избежать понижения каждой переменной-члена в зависимости от производного Response
(и определить более чистую иерархию/дизайн). Например...
ResponseConcreteA response_a;
response_a.deserialize(object_a);
auto data_a = static_cast<DataConcreteA *>(response_a.data.get());
ResponseConcreteB response_b;
response_b.deserialize(object_b);
auto data_b = static_cast<DataConcreteB *>(response_b.data.get());
на первый взгляд очевидное решение — отказаться от полиморфных переменных-членов и заменить ими соответствующие конкретные типы. Однако меня беспокоит то, что это отклонение от неотъемлемого отношения Response
имеющего Data
и Links
членов, каждый из которых относится к определенному полиморфному типу.
Важно отметить, что конкретные типы, приписываемые Data
и Links
, определяются во время компиляции - нет необходимости изменять производные классы в какой-либо момент. Соответствующие конструкции регулируются следующим предварительно обработанным шаблоном:
#define DECLARE_RESPONSE_TYPE(type_name, data_name, links_name \
struct type_name final : public Response \
{ \
type_name() \
{ \
data.reset(new data_name()); \
links.reset(new links_name()); \
} \
~type_name() = default; \
void deserialize(const Poco::JSON::Object::Ptr &payload) override; \
Poco::JSON::Object::Ptr to_json() const override; \
};
Есть ли более подходящий подход, чтобы избежать этих полиморфных переменных-членов в моем дизайне, где требуется постоянное понижение (несмотря на тот факт, что производный объект, на который указывает, известен во время компиляции). Спасибо!
Data
иLinks
, определяется во время компиляции, то эти классы не обязательно должны быть полиморфными. ТогдаResponse
может быть шаблонным типом, параметризованным по типу конкретных типовData
иLinks
. Все, что необходимо тогда, это чтобы все конкретные типы реализовали указанный интерфейс (который, при желании, может быть принудительно реализован путем получения их от абстрактной базы). Кроме того, если конкретные объектыData
иLinks
не создаются динамически, членыResponse
не обязательно должны бытьunique_ptr
— вместо этого они должны быть просто членами этого типа. - person Peter   schedule 04.07.2020Response
. Если этот класс является шаблонным, я предполагаю, что мне придется принять специализацию шаблона и реализовать методыdeserialize
иto_json
в соответствии со специализированными параметрами. Это правильно? - person wubzorz   schedule 04.07.2020