2010-03-13 1 views
3

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

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

ответ

4

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

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

0

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

0

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

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

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

1

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

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

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

#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.

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