【发布时间】:2021-04-20 13:21:19
【问题描述】:
在使用 C++ 中的抽象工厂进行第一次实验时(同时阅读现代 C++ 设计 - A. Alexandrescu - 第 9 部分),我有一个问题。 如果类层次结构如下所示:
struct B {};
struct D1 :public B {};
struct DD1 : public D1 {};
struct DD2 : public D1 {};
struct D2 :public B {};
struct DD3 : public D2 {};
struct DD4 : public D2 {};
我有这个抽象工厂代码:
//abstract factory version 1
struct AbstractFactoryImpl
{
virtual D1* CreateD1() = 0;
virtual D2* CreateD2() = 0;
};
struct AbstractFactory : public AbstractFactoryImpl
{
virtual D1* CreateD1() { return new D1; };
virtual D2* CreateD2() { return new D2; };
};
template<class ... Ts>
struct ConcreteFactory :public AbstractFactory
{
using params = std::tuple<Ts...>;
using T1 = typename std::tuple_element_t<0, params>;
using T2 = typename std::tuple_element_t<1, params>;
virtual D1* CreateD1()override
{
static_assert(std::is_base_of_v<D1, T1>);
return new T1;
};
virtual D2* CreateD2()override
{
static_assert(std::is_base_of_v<D2, T2>);
return new T2;
};
};
并在这样的客户端代码中使用它。
//version 1
AbstractFactory* pFactory;
pFactory = new ConcreteFactory<DD1, DD3>;
D1* pD1 = pFactory->CreateD1();
D2* pD2 = pFactory->CreateD2();
pFactory = new ConcreteFactory<DD2, DD4>;
pD1 = pFactory->CreateD1();
pD2 = pFactory->CreateD2();
它可以满足我的需求,并且看起来像是互联网上的大部分示例。
但是在这个版本的抽象工厂中,如果我想在层次结构(D3、DD5、DD6...)中添加更多类,我必须手动创建太多代码,所以我想让代码更通用。
//abstract factory version 2
template<typename T>
struct AbstractFactoryImpl_
{
virtual T* Create() = 0;
};
template<typename T>
struct AbstractFactory_ :public AbstractFactoryImpl_<T>
{
virtual T* Create() override
{
return new T;
}
};
template<class ...Ts>
struct ConcreteFactory_ : public AbstractFactory_<Ts>...
{
using params = std::tuple<Ts...>;
using T1 = typename std::tuple_element_t<0, params>;
using T2 = typename std::tuple_element_t<1, params>;
template<class T>
T* Create()
{
if constexpr (std::is_base_of_v<T, T1>)return AbstractFactory_<T1>::Create();
else if constexpr (std::is_base_of_v<T, T2>)return AbstractFactory_<T2>::Create();
}
};
它在这样的客户端代码中工作:
//version 2
//AbstractFactory* pFactory; -- can`t use because AbstractFactory in version 2 is template class.
auto pFactory_1 = new ConcreteFactory_<DD1, DD3>;
D1* pD1_ = pFactory_1->Create<D1>();
D2* pD2_ = pFactory_1->Create<D2>();
auto pFactory_2 = new ConcreteFactory_<DD2, DD4>;
pD1_ = pFactory_2->Create<D1>();
pD2_ = pFactory_2->Create<D2>();
所以它可以工作,但我必须创建两个不同的指针(pFactory_1,pFactory_2)指向ConcreteFactory_ 的不同实例。这是抽象工厂没有预料到的。
在第一个版本中,由于虚拟继承可以在基类指针上调用Create。但在这里我有模板基类。所以我不能调用它指针Create()。
所以问题是如何使指针或其他东西可能是 std::any o std::variant 以使其在这个抽象工厂类设计中成为可能?我想要工作的客户端代码和第一个版本一样。
TYPE* pFactory_ = new ConcreteFactory_<DD1, DD3>;
D1* pD1_ = pFactory_->Create<D1>();
D2* pD2_ = pFactory_->Create<D2>();
auto pFactory_ = new ConcreteFactory_<DD2, DD4>;
pD1_ = pFactory_->Create<D1>();
pD2_ = pFactory_->Create<D2>();
完整代码: [https://cppinsights.io/s/552bbe01]
【问题讨论】:
标签: c++ pointers abstract-factory