Вложенный класс или не вложенный класс? - PullRequest
3 голосов
/ 13 марта 2010

У меня есть класс A и список объектов A. A имеет функцию f, которая должна выполняться каждые X секунд (для первого экземпляра каждые 1 секунда, для экземпляра секунд каждые 5 секунд и т. Д.). У меня есть класс планировщика, который отвечает за выполнение функций в нужное время. Я подумал о том, чтобы создать новый класс ATime, который будет содержать ptr для экземпляра A и время A :: f должно быть выполнено. Планировщик будет содержать очередь с минимальным приоритетом Atime.

  1. Как вы думаете, это правильная реализация?
  2. Должен ли ATime быть вложенным классом планировщика?

Ответы [ 4 ]

4 голосов
/ 13 марта 2010

Из того, что вы описываете, звучит так, как будто это может сработать: -)

ИМХО класс ATime принадлежит планировщику больше, чем А. Планировщику необходимо выполнить свою работу, и он не нужен для A. На самом деле, A (и остальной мир) не нужно даже знаю о его существовании - поэтому для меня было бы целесообразно поместить его в частный вложенный класс планировщика.

1 голос
/ 14 марта 2010

Это может быть немного слишком продвинутым, но здесь идет ...

boost :: function и boost :: bind могут использоваться для реализации планировщика, который не должен ничего знать о классе A. Это сделает ваш планировщик более универсальным и многоразовые.

Вот пример кода, который иллюстрирует, как эти возможности Boost могут использоваться в вашем случае:

#include <ctime>
#include <queue>
#include <boost/function.hpp>
#include <boost/bind.hpp>

struct Foo
{
    void onScheduler(time_t time) {/*...*/}
};

struct Bar
{
    void onScheduler(time_t time) {/*...*/}
};

typedef boost::function<void (time_t)> SchedulerHandler;

struct SchedulerEvent
{
    bool operator<(const SchedulerEvent& rhs) const {return when < rhs.when;}

    SchedulerHandler handler;
    time_t when;
};

class Scheduler
{
public:
    void schedule(SchedulerHandler handler, time_t when)
    {
        SchedulerEvent event = {handler, when};
        queue_.push(event);
    }

private:
    std::priority_queue<SchedulerEvent> queue_;
    void onNextEvent()
    {
        const SchedulerEvent& next = queue_.top();
        next.handler(next.when);
        queue_.pop();
    }
};

int main()
{
    Scheduler s;
    Foo f1, f2;
    Bar b1, b2;

    time_t now = time(0);
    s.schedule(boost::bind(&Foo::onScheduler, &f1, _1), now + 1);
    s.schedule(boost::bind(&Foo::onScheduler, &f2, _1), now + 2);
    s.schedule(boost::bind(&Bar::onScheduler, &b1, _1), now + 3);
    s.schedule(boost::bind(&Bar::onScheduler, &b2, _1), now + 4);

    // Do scheduling...

    return 0;
}

Обратите внимание, что Scheduler ничего не знает о Foo & Bar и наоборот. Все, что действительно нужно Scheduler, это функтор обратного вызова, который соответствует сигнатуре, указанной SchedulerHandler.

Если вам нужно SchedulerEvent для отмены, все становится немного сложнее, потому что boost::function объекты несопоставимы. Чтобы обойти это, вам нужно будет вернуть какой-то токен «подключения» при регистрации событий. По сути, это то, что делает Boost.Signal.

Надеюсь, это поможет.

0 голосов
/ 14 марта 2010

Что касается второй части (и вопроса в названии), то IMO это полностью дело вкуса. С таким же успехом вы можете уменьшить помехи в определении класса Scheduler и поместить ATime в пространство имен с именем предупреждения (например, detail), чтобы люди не могли его использовать. В конце концов, если это полезно только для Планировщика, нет особой необходимости слишком сильно его скрывать - никто не захочет его использовать в любом случае.

Возможно, это может быть по-другому в C ++ 0x (я думаю, я слышал некоторые слухи о том, как это изменит правила доступности между вложенным и родительским классом, или около того, в этом случае вложение может быть более целесообразным) 1004 *

Для универсальности вы также можете использовать шаблоны, и, возможно, в итоге получите Scheduler<A> (используя TimedOperation<A>) (или множество возможных уточнений / обобщений этого)?

0 голосов
/ 13 марта 2010

Этот класс лучше всего делать частной структурой, вложенной в ваш класс планировщика, так что вы можете легко получить доступ ко всем полям внутри класса планировщика. (По умолчанию все поля структуры общедоступны.)

...