我正在编写一个接口,它基本上有两个方法next
尝试获取下一个值,prev
返回前一个值。
struct foo
{
virtual boost::optional<int> next() = 0;
virtual int prev() = 0;
};
首先调用next
将基本上使用该接口,如果失败,则可以使用prev
获取前一个值。 prev
并不像这个例子那样微不足道,prev
值会发生其他一些事情。 prev
方法对所有类的工作方式基本相同,我想提供它的默认实现。
我必须实现这个方法,我都不喜欢:
第一种可能性是抽象基类而不是接口。
struct abstract_foo : public foo
{
int prev_;
virtual boost::optional<int> next()
{
boost::optional<int> val = do_next();
if(val)
prev_ = *val;
return val;
}
int prev()
{
return prev_;
}
virtual boost::optional<int> do_next() = 0;
};
然而,它打破了界面,现在要么必须记住要调用abstract_foo::next
,要么被迫实施一个相当丑陋的do_next
。
另一种方法是使用装饰器:
struct foo
{
virtual boost::optional<int> next() = 0;
virtual int prev()
{
throw not_implemented();
}
};
struct foo_decorator : public foo
{
std::unique_ptr<foo> foo_;
int prev_;
foo_decorator(std::unique_ptr<foo>&& foo)
: foo_(std::move(foo))
{
}
boost::optional<int> next()
{
boost::optional<int> val = foo_->next_value();
if(val)
prev_ = *val;
return val;
}
int prev()
{
return prev_;
}
};
在这里,not_implemented
只是在用户认为可以直接从基类使用prev
的事故中尖叫。
有没有人对好的设计有好的建议?或者我应该只是有一些辅助类来帮助在派生类中手动实现它?
答案 0 :(得分:3)
您的第一个选项实际上接近首选方式,如下所示:
class foo
{
public:
boost::optional<int> next()
{
boost::optional<int> val = do_next();
if(val)
prev_ = val;
return val;
}
int prev()
{
return prev_;
}
private:
int prev_;
virtual boost::optional<int> do_next() = 0;
};
请注意next()
和prev()
是非虚拟的,do_next()
是私有的。 Public non-virtual interface calls private virtual implementation
答案 1 :(得分:0)
在第二个选项中,为什么不在基类中实现prev:
struct foo
{
public:
virtual boost::optional<int> next() = 0;
int prev()
{
return prev_;
}
protected:
int prev_;
};
struct foo_decorator : public foo
{
std::unique_ptr<foo> foo_;
foo_decorator(std::unique_ptr<foo>&& foo)
: foo_(std::move(foo))
{
}
boost::optional<int> next()
{
boost::optional<int> val = foo_->next_value();
if(val)
prev_ = *val;
return val;
}
};