我在为以下场景寻找简单而优雅的设计时遇到了麻烦。类Worker
使用模板类Helper
来完成一些工作。在简单的场景中,它看起来像这样:
template<typename T>
class Helper {
public:
void Help(T data) : m_data(data) {} //NOTICE: Copy
T const& Data() const { return m_data; }
T m_data;
}
class SimpleWorker {
public:
SimpleWorker() : m_helper(SimpleData()) {} // non-temp used in reality
void DoWork()
{
m_helper.help();
}
Helper<SimpleData> m_helper;
}
当模板参数更复杂并且与工作者的业务域相同时,事情变得复杂。 worker需要使用帮助器,但是它还需要调用帮助程序甚至不知道的数据对象上的某些方法(在本设计中)。类似的东西:
template<typename T>
class Helper {
public:
Helper(T data) : m_data(data) {} //NOTICE: Copy
T const& Data() const { return m_data; }
T m_data;
}
class ComplexWorker {
public:
ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality
void DoWork()
{
m_helper.help();
m_helper.GetData().DoSomethingComplexNotConst(); // <-------------
}
Helper<ComplexData> m_helper;
}
显而易见的问题是我无法在Data()
结果上调用非const函数。使Data()
非const看起来是个坏主意,因为Helper
也用于不同的上下文。我的目标是找到一种优雅的方式来改变ComplexData
使用ComplexWorker
中的成员函数
首先需要更改ComplexData
,以便Helper
可以继续使用更改的数据。
编辑:更改Helper
构造以复制提供的数据以更好地类似于实际流量
答案 0 :(得分:1)
我认为最好让Helper
只有静态函数,而不是维护状态(在你自己的代码中ComplexData()
创建临时ComplexWorker
)。根据您是否需要修改,通过引用或const引用传递数据。
// primary template
template<typename T>
class Helper {
public:
static void help(T const& data) const {} // non-modifying
};
// specialization for ComplexData
template<>
class Helper<ComplexData> {
public:
static void help(ComplexData const& data) const { } // non-modifying
static void DoSomethingComplexNotConst(ComplexData& data) // modifying
{
// your implementation here
}
};
class ComplexWorker {
public:
ComplexWorker() : m_data(ComplexData()) {} // create new data
void DoWork()
{
Helper<ComplexData>::help(m_data);
Helper<ComplexData>::DoSomethingComplexNotConst(m_data); // <--- now no problem
}
private:
ComplexData m_data;
};
请注意,我为ComplexData
制作了模板专精。 help()
中存在一些代码重复,但您可以轻松地将其提取到一个常见的非成员帮助函数中。
答案 1 :(得分:0)
在我看来,这取决于Helper
实际上在做什么。你的例子只给出了一个构造函数和一个访问器,但我怀疑它是否在实践中完成。
你考虑过简单地使用继承吗?您的Helper
模板将如下所示:
template<typename T>
class Helper : public T {
Helper(T data) : T(data) {}
void Help() {};
}
在这种情况下,您可以直接在'is-a'关系中使用Helper<ComplexData>
对象:
class ComplexWorker {
Helper<ComplexData> m_helper;
void DoWork()
{
m_helper.help();
m_helper.DoSomethingComplexNotConst();
}
}
答案 2 :(得分:0)
为什么不参考STL中Container部分的实现。 Data()函数的重载可以实现安全和优雅之间的平衡。
template <typename T>
class Helper {
public:
Helper(T data) : m_data(data) {} //NOTICE: Copy
T const& Data() const { return m_data; }
T& Data() {return m_data; }
private:
T m_data;
}
class ComplexWorker {
public:
ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality
void DoWork()
{
m_helper.help();
ComplexData &cd1 = m_helper.Data();
cd1.QuerySth();
const ComplexData &cd2 = m_helper.Data();
cd2.ModifySth();
}
private:
Helper<ComplexData> m_helper;
}