我有一个设计问题,实际上并不复杂,但我想找到一种优雅的方法来解决它。我想到了这个:
问题: 我有一个A类初始化并保留B
的集合 B只是一个接口,必须实现(所以我们有类C,D,E,..)。
重新获取一堆数据集,并且必须在给定每个数据集的情况下初始化一些B(也是相同或不同类的不同实例)。我希望A不知道任何实施B.
我有几个工作解决方案,但我正在考虑一种“构造函数中的委托”。 例如:
1. for each dataset, ds
2. for each implementation of B, bi
3. try to instantiate bi(ds)
4. if success (means no exception)
5. keep reference
这是因为我使用的数据和微积分来检查bi是否与初始化非常相似并且在一个性能评论应用程序中我想避免这样做两次或者在集合类中这样做。
它会非常好,但显然问题是第2行......
...以及对实际上不是例外的事情使用异常的疑问。 (第4行)
那么什么应该是一种模式
- 让我评估数据并构建一体化
- 避免创建几个“架构类”我想避免类的爆炸(对于这样一个简单的任务,使用以下设计模式java风格原则imho进行扩展时的典型)。
- 尽可能快。
- ...很优雅:)
答案 0 :(得分:2)
答案是基于我现在的直觉,所以它可能并不完美,但另一方面,大多数设计解决方案都不是。
我只会创建一个额外的类,称之为工厂或类似的东西。然后通过这个类运行所有构造。它应该能够在运行时(通过在程序开始时运行回调),或者甚至更好地通过可变参数模板特征,使用可能的B派生实例化进行初始化。
template<class ... RegisteredBImplementations>
class CFactory
{
B* Create (dataset const& d)
{
// some magical meta-ifs to create compile time conditions
// or for (auto& registered_type : registered types), and then choose one
return new T(d);
}
}
然后,A可以使用此类的实例来正确初始化它的指针:
for (auto& dataset : datasets)
{
m_BPtrs.emplace_back( std::unique_ptr<dataset> (m_FactoryInstance.Create(dataset)) );
}
这个解决方案的要点是A类有效地管理“B”对象,将它们正确地构建到另一个类。它们实际上是分开的,添加新的B
实现意味着仅在CFactory
中进行更改,而不是在A
中进行更改。
答案 1 :(得分:1)
最简单的解决方案是委托Factory方法。
std::unique_ptr<B> build(DataSet const& ds) {
if (ds.property() == value) {
return std::unique_ptr<B>(new D(ds));
}
return std::unique_ptr<B>(new C(ds));
}
然后A
只需要依赖build
的声明。
答案 2 :(得分:1)
您的伪代码提出了一个解决方案:使用bi
只不过是一个工厂函数,它以dataset
作为输入并返回B*
作为输出。所以,你真的需要从bi
个对象的集合中获取std::function<B* (dataset)>
。
要求这些工厂只是“有条件”的工厂是很容易的:有时他们会返回有效的对象,有时他们却没有,返回nullptr
。这样可以避免异常,并且更忠实于您的使用意图。