如何重构具有相同行的函数,唯一不同的是一个函数调用?
how to refactor functions that have same lines with only difference being one function call?
考虑以下代码片段
template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
// change in function call
m_block.DefaultConstruct();
}
}
}
这里是相同函数的重载
template<typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
// change in function call
m_block.CopyConstruct(object);
}
}
}
我认为重构调整大小函数的一种方法是提供 const T *pObject 作为默认参数。并检查是否提供,然后调用 CopyConstruct.
可以提供另一种方法,使一个调整大小成为一种调用另一个调整大小的包装器。
最好的方法是什么?
没有"the best approach"这样的东西可以普遍适用于所有可能的情况。例如,如果代码膨胀不是一个问题,你可以有一对公共函数的外观,将适当的 lambda 传递给公共函数:
template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
resize_common(count, [] { m_block.DefaultConstruct(); });
}
template <typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
resize_common(count, [&] { m_block.CopyConstruct(object); });
}
template <typename T, typename lambda_t>
void MyDynamicArray<T>::resize_common(size_t count, lambda_t &&lambda)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
lambda();
}
}
}
如果代码膨胀是一个问题,那么您自己提供的一种可能性的变体:
template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
resize_common(count, null);
}
template <typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
resize_common(count, &object);
}
template <typename T>
void MyDynamicArray<T>::resize_common(size_t count, const T *object)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
if (object)
m_block.CopyConstruct(*object);
else
m_block.DefaultConstruct();
}
}
}
我相信人们可以想到相同的一些变体。最重要的是,要回答 "which one is the best",必须考虑您的个人需求,考虑每个替代实现满足需求的程度,然后选择其中之一。代码膨胀应该最小化吗?整体性能有问题吗?等...
一个解决方案是创建一个虚拟对象,您可以将其传递给新函数 m_block.Construct()
以表明它是默认构造:
struct default_construct_t { };
我们像这样使用:
template <typename T>
void MyDynamicArray<T>::resize(size_t count) {
resize(count, default_construct_t());
}
template <typename T, typename Obj>
void MyDynamicArray<T>::resize(size_t count, Obj const& obj)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
// change in function call
m_block.Construct(obj);
}
}
}
现在您只需为 Construct(default_construct_t )
和 Construct(T const& )
提供重载。
考虑以下代码片段
template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
// change in function call
m_block.DefaultConstruct();
}
}
}
这里是相同函数的重载
template<typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
// change in function call
m_block.CopyConstruct(object);
}
}
}
我认为重构调整大小函数的一种方法是提供 const T *pObject 作为默认参数。并检查是否提供,然后调用 CopyConstruct.
可以提供另一种方法,使一个调整大小成为一种调用另一个调整大小的包装器。
最好的方法是什么?
没有"the best approach"这样的东西可以普遍适用于所有可能的情况。例如,如果代码膨胀不是一个问题,你可以有一对公共函数的外观,将适当的 lambda 传递给公共函数:
template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
resize_common(count, [] { m_block.DefaultConstruct(); });
}
template <typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
resize_common(count, [&] { m_block.CopyConstruct(object); });
}
template <typename T, typename lambda_t>
void MyDynamicArray<T>::resize_common(size_t count, lambda_t &&lambda)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
lambda();
}
}
}
如果代码膨胀是一个问题,那么您自己提供的一种可能性的变体:
template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
resize_common(count, null);
}
template <typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
resize_common(count, &object);
}
template <typename T>
void MyDynamicArray<T>::resize_common(size_t count, const T *object)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
if (object)
m_block.CopyConstruct(*object);
else
m_block.DefaultConstruct();
}
}
}
我相信人们可以想到相同的一些变体。最重要的是,要回答 "which one is the best",必须考虑您的个人需求,考虑每个替代实现满足需求的程度,然后选择其中之一。代码膨胀应该最小化吗?整体性能有问题吗?等...
一个解决方案是创建一个虚拟对象,您可以将其传递给新函数 m_block.Construct()
以表明它是默认构造:
struct default_construct_t { };
我们像这样使用:
template <typename T>
void MyDynamicArray<T>::resize(size_t count) {
resize(count, default_construct_t());
}
template <typename T, typename Obj>
void MyDynamicArray<T>::resize(size_t count, Obj const& obj)
{
size_t prev_count = Count();
if(count < prev_count)
{
DestroyMemory(prev_count, count);
}
else if(count > prev_count)
{
Reserve(count);
for(size_t i=prev_count; i<count; i++)
{
// change in function call
m_block.Construct(obj);
}
}
}
现在您只需为 Construct(default_construct_t )
和 Construct(T const& )
提供重载。