这更像是一个,我很想知道它是否有意义问题,而不是一个,我有一个真正的问题,我在你的意见中强调。如果存在任何语法错误,我使用伪代码来说明要描述的意图。
我有一个使用for循环的程序。
for (frame_pos = 0; frame_pos < frame_size; frame_pos++) {
ABC...
}
现在我想添加另一种可能的方法来迭代我的程序。
for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
ABC...
}
所以我写了一个if语句
if(a == true){
for (frame_pos = 1; frame_pos <= frame_size; frame_pos++) {
ABC...
}
}else{
for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
ABC...
}
}
但不知怎的,我不喜欢它,因为我复制了我的代码。
ABC...
当然,我可以将所有内容从循环中移动到方法中,并且只调用该方法。但我想知道,如果像
那样的话switch(a){
case(true):
for (frame_pos = 1; frame_pos <= frame_size; frame_pos++) {
break;
default:
for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
break;
}
是可能的,如果可能的话,有用且有意义,因为我会在这里使用它。当然,它不一定必须是switch-case
它可能是其他一些机制。但我的目的是从我的角度分割atomic
for( ; ; ) {
...
}
身体并重新组合它。
答案 0 :(得分:4)
让ABC
成为一个函数(extract method)并调用它。
答案 1 :(得分:4)
如果你不想在运行期间在两种方法之间切换,你可以在预处理器级别解决这个问题:
#define _USENEXT /* Comment out this line to use the "counter" approach. */
...
for (
#ifdef _USENEXT
frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext
#else
frame_pos = 1; frame_pos <= frame_size; frame_pos++
#endif
)
{
<some code>
}
作为代码中#define
_USENEXT
的替代方法,我可以在编译时将其指定为选项。对于gcc,这将是-D _USENEXT
。
答案 2 :(得分:3)
某些语言具有轻松使这些模式可重用的机制。例如,C#会让你写下类似的内容:
IEnumerable<Frame> Frames1() {
for (frame_pos = 0; frame_pos < frame_size; frame_pos++) {
yield return framelist[framepos];
}
}
IEnumerable<Frame> Frames2() {
for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
yield return framelist[framepos];
}
}
然后您可以将这些迭代模式视为与其他任何类似的第一类对象。
foreach(var frame in a? Frames1() : Frames2()) {
ABC...
}
使用这样的功能,您可以避免实现细节,例如来自C的循环的那些愚蠢的样板低级错误原语。
C ++没有这样的语法特性,但它也有一个类似的重用迭代模式的机制:迭代器。编写迭代器并不像在C#中那样简单,但是:(
但是标准容器已经提供了合适的迭代器。然后,您可以重用标准库中提供的许多现有迭代模式中的任何一种。
std::vector<int> v = ...;
std::set<int> s = ...;
auto are_equal = std::equal(v.begin(), v.end(), s.begin(), s.end());
好的C ++库也会类似地提供合适的迭代器。 (是的,祝你好运;看起来很多人写“C ++库”并不知道C ++)
答案 3 :(得分:2)
如果你真的不想让ABC成为一个函数然后在两个不同的for循环之间切换,你可以改为编写三个函数:
int initFramepos( int a )
{
return( a ? 1 : framelist.first );
}
int checkFramepos( int frame_pos, int a )
{
return( a ? frame_pos < frame_size ? framelist.hasNext );
}
int incrFramepos( int frame_pos, int a )
{
return( a ? frame_pos+1 ? framelist.getNext );
}
然后你的for循环看起来像这样:
for( frame_pos = initFramepos( a ); checkFramepos( frame_pos, a ); frame_pos = incrFramepos( frame_pos, a ) )
{
ABC
}
答案 4 :(得分:2)
干净的解决方案(用于C ++代码 - 这对C不起作用)将为您的特定情况编写迭代器类实现。然后,您可以根据迭代器编写客户端代码,并确定迭代的含义与其实现方式无关(您可以随时决定迭代对您的意义,而无需更改客户端代码)。 / p>
如果你这样做并专门化std::begin
和std::end
,你将能够在std中使用整个迭代器算法库作为奖励:(sort
,copy
,find/find_if
,for_each
,all_of
,any_if
,transform
和accumulate
是最有用的,在我的头脑中。
关于其他解决方案,请不要使用宏:它会导致脆弱的代码,很多难以看到的警告。根据经验,在C ++中使用宏应该(接近)最后考虑的任何解决方案。
答案 5 :(得分:1)
您在此描述的正是战略模式旨在解决的问题。 基本上,你需要做的是将每个循环作为一个类中的方法,然后将其中一个作为策略。当然,您可以随时在策略之间切换。
它看起来像这样:
class Strategy {
virtual void func () = 0;
};
class StrategyA : public Strategy {
virtual void func () {
for (frame_pos = 0; frame_pos < frame_size; frame_pos++) {
ABC...
}
}
};
class StrategyB : public Strategy {
virtual void func () {
for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
//ABC...
}
}
};
class StrategyToTake {
private:
Strategy* strategy;
public:
void execute () {strategy->func();}
void setStrategy (Strategy* newStrategy) {this.strategy = newStrategy;}
};