Я пишу интерфейс, который в основном имеет два метода: 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
непосредственно из базового класса.
Есть ли у кого-нибудь хорошее предложение для хорошего дизайна? Или мне просто нужен какой-то вспомогательный класс, который помогает реализовать его вручную в производных классах?