2010-03-13 6 views
3

J'ai la classe A et la liste d'objets A. A a une fonction f qui devrait être exécutée toutes les X secondes (pour la première instance toutes les secondes, pour l'instance des secondes toutes les 5 secondes, etc.). J'ai une classe de planificateur chargée d'exécuter les fonctions au bon moment. Ce que je pensais faire est de créer une nouvelle classe, ATime, qui tiendra ptr à une instance et le temps A :: f devrait être exécuté. Le planificateur tiendra une file d'attente de priorité minimale de Atime.Classe imbriquée ou classe imbriquée?

  1. Pensez-vous que c'est la bonne implémentation?
  2. ATime doit-il être une classe imbriquée du planificateur?

Répondre

4

D'après ce que vous décrivez, sonne comme cela pourrait fonctionner :-)

classe à mon humble avis ATime appartient au planificateur plus A. Il est nécessaire pour le planificateur de faire son travail, et ce n'est pas nécessaire pour A. En fait, A (et le reste du monde) n'ont même pas besoin de connaître son existence - donc le placer dans une classe imbriquée privée de l'ordonnanceur me conviendrait.

0

Ce type de classe est mieux structuré dans votre classe de planificateur, vous pouvez donc accéder facilement à tous les champs de la classe du planificateur. (Tous les champs d'une structure sont publics par défaut.)

0

En ce qui concerne la deuxième partie (et la question dans le titre), IMO c'est une question de goût. Vous pouvez tout aussi bien choisir de réduire le fouillis dans la définition de la classe Scheduler, et placer ATime dans un sous-espace de noms avec un nom d'avertissement (comme detail) pour empêcher les gens de l'utiliser. Après tout, si c'est seulement utile pour le planificateur, il n'y a pas grand besoin de le cacher trop - personne ne voudra l'utiliser quand même. Peut-être cela pourrait-il être différent en C++ 0x (je pense que j'ai entendu des rumeurs sur la façon dont il va changer les règles d'accessibilité entre la classe imbriquée et la classe parent, auquel cas l'imbrication pourrait être plus intéressante).

Pour la généricité, vous pouvez également utiliser des modèles, et peut-être finir avec Scheduler<A> (en utilisant un TimedOperation<A>) (ou une myriade d'améliorations/généralisations potentielles de cela)?

1

Cela peut être un peu trop avancé, mais ici ...

boost::function et boost::bind peut être utilisé pour mettre en œuvre un programmateur qui n'a pas besoin de savoir quoi que ce soit au sujet de la classe A. Cela rendrait votre planificateur plus générique et réutilisable.

Voici quelques exemples de code qui illustre comment ces installations Boost peuvent être utilisés dans votre cas:

#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; 
} 

Notez que Scheduler sait rien Foo & Bar, et vice-versa. Tous les Scheduler veut vraiment un foncteur "callback" qui correspond à la signature spécifiée par SchedulerHandler.

Si vous avez besoin d'un SchedulerEvent pour être annulable, les choses deviennent un peu compliquées car les objets boost::function ne sont pas comparables. Pour contourner cela, vous devrez retourner une sorte de jeton "connexion" lors de l'enregistrement des événements. C'est essentiellement ce que fait Boost.Signal.

Espérons que cela aide.

Questions connexes