我有两个性能关键的功能:
insertExpensive(Holder* holder, Element* element, int index){
//............ do some complex thing 1
holder->ensureRange(index);//a little expensive
//............ do some complex thing 2
}
insertCheap(Holder* holder, Element* element, int index){
//............ do some complex thing 1
//............ do some complex thing 2
}
如何将2个功能组合在一起以提高可维护性?
解决方案1。
insertExpensive(Holder* holder, Element* element, int index){
do1();
holder->ensureRange(index);//a little expensive
do2();
}
insertCheap(Holder* holder, Element* element, int index){
do1();
do2();
}
这将是丑陋的。
如果do2
需要do1
的某些局部变量,那么这也是不切实际的。
解决方案2。
insert(Holder* holder, Element* element, int index, bool check){
//............ do some complex thing 1
if(check)holder->ensureRange(index);//a little expensive
//............ do some complex thing 2
}
每次通话都需要进行条件检查。
解决方案3。(草稿)
template<bool check> insert(Holder* holder, Element* element, int index){
//............ do some complex thing 1 (Edit2 from do1());
bar<check>();
//............ do some complex thing 2 (Edit2 from do2());
}
template <>
inline void base_template<true>::bar() { holder->ensureRange(index); }
template <>
inline void base_template<false>::bar() { }
过度杀伤和不必要的复杂性?
编辑1:
方法有多好的标准优先顺序如下: -
1.最佳表现
2.减少代码重复
3.减少总代码行数
4.更容易阅读专家和初学者
编辑2:编辑第3个解决方案。感谢mvidelgauz和Wolf。
答案 0 :(得分:6)
你的解决方案2实际上还不是那么糟糕。如果此代码在标头内,则将其隐式地视为内联代码。 (我已经明确地写过)如果用true或false调用它,编译器可以删除if语句,尽管它取决于一系列因素来知道它是否会这样做。 (内联后的整体尺寸,常数的可见性,调整......)
String username;
int phone1;
@Override
public void widgetSelected(SelectionEvent e) {
try
{
phone1 = Integer.parseInt(phone.getText());
}
catch (Exception exe)
{
MessageDialog.openError(shell, "Error","Phone number has to be a number");
return;
}
try
{
username = namefield.getText();
if (username!= "admin") {
throw (new Exception());
}
}
catch (Exception exe)
{
MessageDialog.openError(shell, "Error","The username must be admin");
return;
}
labelresult.setText("The name entered is:"+ username );
labelresult2.setText("The phone entered is:"+ phone1 );
解决方案3实际上是您想要实现的,因为模板需要为每个不同的调用进行新的函数实例化,因此它将删除死代码。但是,它的编写方式与编写解决方案2的方式非常相似。
inline void insert(Holder* holder,Element* element,int index, bool check){
do1();
if (check)
holder->ensureRange(index);//a little expensive
do2();
}
如果您有C ++ 17,则不再需要依赖编译器来删除死代码,因为您可以强制它通过constexpr-if跳过某些代码。这种结构将保证删除if语句中的代码,因为它甚至不需要编译。
template <bool check>
inline void insert(Holder* holder,Element* element,int index){
do1();
if (check)
holder->ensureRange(index);//a little expensive
do2();
}
答案 1 :(得分:2)
insert(Holder* holder,Element* element,int index, bool ensureRange){
//............ do some complex thing 1
if (ensureRange){
holder->ensureRange(index);//a little expensive
}
//............ do some complex thing 2
}
如果您可以在编译时做出决定并希望使用模板:
template<bool check> insert(Holder* holder,Element* element,int index){
//............ do some complex thing 1;
if(check)holder->ensureRange(index);
//............ do some complex thing 2
}
insert<true>(...); //expensive operation
insert<false>(...); //cheap operation
答案 2 :(得分:1)
让我们假设你做了以下结构:
定义两个受保护方法do1
和do2
以及公共抽象方法Insert
的类。
class BaseHolder
{
proteted:
void do1(/* complete with necessary parameters*/)
{
}
void do2(/* complete with necessary parameters*/)
{
}
public:
abstract void Insert(Holder* holder, Element* element, int index);
};
class Expensive : BaseHolder
{
public:
void Insert(Holder* holder, Element* element, int index)
{
do1();
holder->ensureRange(index);
do2();
}
};
class Cheap : BaseHolder
{
public:
void Insert(Holder* holder, Element* element, int index)
{
do1();
do2();
}
};
很抱歉,如果我犯了一些语法错误,但这是我看到解决方案的方式。
另一种可能性是制作一个自定义Cheap
和Expensive
类,它们都包裹Holder
,并在Expensive
构造函数中执行范围验证:
class Base
{
protected:
Holder* _holder;
public:
Holder* GetHolder(){ return _holder; }
}
class Cheap : Base
{
public:
Cheap(Holder* holder)
{
_holder = holder;
}
};
class Expensive : Base
{
public:
Expensive(Holder* holder)
{
holder->ensureRange(index);
_holder = holder;
}
};
使用廉价和昂贵的对象作为Insert
方法的参数。
我想第二种解决方案比第一种解决方案更好。
一个更像第一个的解决方案,但它使用了模板方法设计模式,最好是最终:
class BaseHolder
{
proteted:
void do1(/* complete with necessary parameters*/)
{
}
void do2(/* complete with necessary parameters*/)
{
}
virtual void check(Holder* holder, int index){ };
public:
void Insert(Holder* holder, Element* element, int index)
{
do1();
check(holder, index);
do2();
};
class Expensive : BaseHolder
{
protected:
override void check(Holder* holder, int index)
{
holder->ensureRange(index);
}
};
class Cheap : BaseHolder
{
};
此解决方案仅在check
对象上定义Expensive
方法,它具有最多的代码重用,并且它绝对是最干净的方法之一。不幸的是,这是关于oop设计而不是关于性能不是最好的,但你必须考虑哪个是你的优先事项,正如你刚刚总结的那样。
答案 3 :(得分:1)
从技术上讲,我更喜欢像mvidelgauz's answer中所示的解决方案,但是由于不能自我解释的文字true
或{{{{}}},因此必须实际调用函数时添加的参数看起来很糟糕1}}。所以我将三个函数组合在一起:一个内部(false
)函数,它提供了一个参数检查标志,以及两个外部函数,提供了关于函数的明显名称,我更喜欢像private
这样的函数。 ,checkedInsert
。然后,这些公共函数将调用4参数实现。
在下面的代码片段中减少了大部分参数,使解决方案最为明显。它应该被视为类定义的一个片段:
uncheckedInsert
此解决方案提供:最佳用户界面和一致的实施。
顺便说一句:
我真的怀疑单个条件检查会导致真正的性能问题。
答案 4 :(得分:0)
作为另一种选择,您可以简单地使用默认函数参数,默认值对应于无范围检查
void insert(Holder* holder, Element* element, int index,
bool performRangeCheck = false)
{
/* do some complex thing 1 */
if(performRangeCheck)
{
holder->ensureRange(index);
}
/* do some complex thing 2 */
}
// ...
insert(holder, element, 2); // no range check
insert(holder, element, 2, true); // perform range check