重构 — 改善既有的类图设计 条款12:消除聚合内部的返回参数的复制
黄国强 2008-10-07
上文说到,CInner 如果本身很大的话,会有一个复制开销。这个依然可以通过设计来解决。方法很多,比如写一个句柄类引入引用计数就可以。我这里介绍的是我自己发明的一种方法,自认为比较简单。
首先我们把 CInner 变成一个不变的值对象。如下面的示例中,所有的Set函数都取消。
// 负责表示一个聚合类内部的类
class CInner
{
...
public:
void SetVal(double dVal); // 取消这个函数
double GetVal(void)const;
private:
...
};
CAggregate 修改后的代码实现请看下面。
// 负责表示聚合类
class CAggregate
{
...
public:
boost::shared_ptr<CInner> GetInner(void)const // 此处返回值修改成返回一个boost::shared 指针,没有复制开销
{
return m_pInner;
}
void SetInner(boost::shared<CInner> pNewVal)
{
m_pInner.reset(new CInner(*pNewVal.get())); // 此处调用了 CInner 的复制构造函数重新分配一个新的对象并赋值给 m_pInner
}
private:
boost::shared_ptr<CInner> m_pInner;
...
};
由于 CInner 是一个不变的值对象,所以即使持有 boost::shared<CInner> 指针也无法修改 CAggregate 内部的 m_pInner 成员,从而完整性得到保证。
图一为引入 boost::shared_ptr 模板重构后的图。关于 boost::shared_ptr 的详细请参阅 boost 库的相关资料,本文不作展开。
图一