IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Discussion :

design pattern Singleton

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    47
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 47
    Points : 11
    Points
    11
    Par défaut design pattern Singleton
    Hello'

    -> J'ai découvert les singleton, c'est ce qu'il me fallait.
    -> J'ai aucune connaissances sur le sujet, je fais que découvrir... j'aimerais savoir pourquoi ca ne marche pas
    -> pitié des mots simples dans vos reponses, je débute...

    -> mon but: rendre MainWindow singleton, et ensuite rendre SocketHandler singleton... Mais si j'y arrive une fois, je devrais pouvoir le faire deux fois.

    L'erreur qui s'affiche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    debug/main.o(.text+0x16a): In function `Z5qMainiPPc':
    C:/dev/HighStory/main.cpp:11: undefined reference to `Singleton<MainWindow>::Get()'
    debug/sockethandler.o(.text+0x4f5): In function `ZN13SocketHandler3lolEv':
    C:/dev/HighStory/sockethandler.cpp:16: undefined reference to `Singleton<MainWindow>::Get()'
    main.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <QtGui/QApplication>
    #include "mainwindow.h"
    #include "sockethandler.h"
    #include "designpatterns.h"
     
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
     
     
    MainWindow* w=Singleton<MainWindow>::Get();
     
        w->show();
        w->showLogin();
     
     
        SocketHandler sh;
        sh.lol();
        return a.exec();
    }
    sockethandler.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include "sockethandler.h"
    #include "global_variables.h"
    #include "mainwindow.h"
    #include "designpatterns.h"
     
    SocketHandler::SocketHandler()
    {
        _qts = new QTcpSocket();
        _qts->connectToHost(QString(QTS_CONNECT_ADDRESS),QTS_CONNECT_PORT);
        qDebug("woot connected");
    }
     
     
    void SocketHandler::lol()
    {
        MainWindow* w=Singleton<MainWindow>::Get();
        w->errorAlert("LOOL");
    }
    mainwindow.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "global_variables.h"
     
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent), ui(new Ui::MainWindowClass)
    {
        ui->setupUi(this);
    }
     
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    void MainWindow::showLogin()
    {
        // creating the login widget
        qmwLogin = new QWidget(this);
        qmwLogin->setObjectName(QString(QMW_LOGIN));
        qmwLogin->setGeometry(QRect(this->geometry().left(),this->geometry().top(),this->geometry().width(),this->geometry().height()));
        // now the controls
        leAccountID = new QLineEdit(qmwLogin);
        lePassword  = new QLineEdit(qmwLogin);
        pbLogin   = new QPushButton(qmwLogin);
        // names of em
        leAccountID->setObjectName(QString(QMW_LOGIN_ACCOUNTID));
        lePassword->setObjectName(QString(QMW_LOGIN_PASSWORD));
        pbLogin->setObjectName(QString(QMW_LOGIN_BTNLOGIN));
        // positioning
        leAccountID->setGeometry(QRect(qmwLogin->geometry().left()+100,qmwLogin->geometry().top()+100,60,20));
        lePassword->setGeometry(QRect(qmwLogin->geometry().left()+100,qmwLogin->geometry().top()+130,60,20));
        pbLogin->setGeometry(QRect(qmwLogin->geometry().left()+120,qmwLogin->geometry().top()+160,40,20));
        pbLogin->setText("Log in");
        // signals
        connect(pbLogin,SIGNAL(clicked()),this,SLOT(doLogin()));
        // show 'em
        leAccountID->show();
        lePassword->show();
        pbLogin->show();
     
        setCentralWidget(qmwLogin); // sets central widget
    }
    void MainWindow::hideLogin()
    {
        delete qmwLogin;
    }
    void MainWindow::doLogin()
    {
        QString *enteredAccountID = new QString(leAccountID->text());
        if(enteredAccountID->isEmpty() || enteredAccountID->isNull()) errorAlert(QString(ERROR_MISSING_ACCOUNTID));
        else {
            // preparating a packet to send.
            // sends it.
        }
     
    }
    void MainWindow::errorAlert(QString msg)
    {
        qmwErrorBox = new QWidget(this);
        qmwErrorBox->setGeometry(QRect(this->geometry().width()/2-150,this->geometry().height()/2-70,300,140));
        QLabel *ebMessage = new QLabel(qmwErrorBox);
        ebMessage->setGeometry(QRect(10,10,280,70));
        ebMessage->setText(msg);
        QPushButton *ebOk = new QPushButton(qmwErrorBox);
        ebOk->setGeometry(QRect(110,90,80,40));
        ebOk->setText("Ok");
        connect(ebOk,SIGNAL(clicked()),this,SLOT(errorOk()));
        qmwErrorBox->show();
    }
    void MainWindow::errorOk()
    {
        delete qmwErrorBox;
    }
    mainwindow.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #include <QtGui/QMainWindow>
    #include <QChar>
    #include <QLineEdit>
    #include <QPushButton>
    #include <QFile>
    #include <QTextStream>
    #include <QLabel>
     
    #include "designpatterns.h"
     
    namespace Ui
    {
        class MainWindowClass;
    }
    class MainWindow : public QMainWindow, public Singleton<MainWindow>
    {
        Q_OBJECT
     
        friend MainWindow* Singleton<MainWindow>::Get();
        friend void Singleton<MainWindow>::Kill();
     
    public:
        void showLogin();
        void hideLogin();
        void errorAlert(QString msg);
    public slots:
        void doLogin();
        void errorOk();
     
    private:
        MainWindow (const MainWindow&){}
        MainWindow(QWidget *parent = 0);
        ~MainWindow();
        Ui::MainWindowClass *ui;
        QWidget *qmwLogin;
            QLineEdit *leAccountID;
            QLineEdit *lePassword;
            QPushButton *pbLogin;
        QWidget *qmwErrorBox;
    };
    designpatterns.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    #include "designpatterns.h"
    template <class T> T* Singleton<T>::m_i=0;
     
     
    template <class T>  T* Singleton<T>::Get()
    {
            if(m_i==0)
            {
                    m_i=new T();
            }
            return m_i;
    }
     
    template <class T> void Singleton<T>::Kill()
    {
            delete m_i;
            m_i=0;
    }
    designpatterns.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <class T> class Singleton
    {
    public:
            static T* Get();
            static void Kill();
    protected:
            static T* m_i;
            private:
            T& operator= (const T&){}
    };

  2. #2
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Salut,

    l'exception qui confirme la règle: le corps des fonctions (ie. le contenu de designpatterns.cpp) doit être inclus dans le même fichier que celui qui définit la classe elle-même (donc designpatterns.h).
    C'est le seul cas de figure (ie. dans les templates) où c'est obligatoire.

    A noter que le singleton n'est pas le saint Graal des patterns et c'est normalement un pattern à éviter (on l'appelle parfois 'anti-pattern') car on en arrive vite à accéder à l'objet singleton (ici la MainWindow) depuis n'importe où à tort et à travers, au lieu de se poser la bonne question tout de suite : "n'y a-t-il pas un souci dans mon architecture ?".

    références sur l'utilisation excessive de singletons :
    - en Anglais ici
    - traduction français ici
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Points : 969
    Points
    969
    Par défaut
    l'exception qui confirme la règle: le corps des fonctions (ie. le contenu de designpatterns.cpp) doit être inclus dans le même fichier que celui qui définit la classe elle-même (donc designpatterns.h).
    C'est le seul cas de figure (ie. dans les templates) où c'est obligatoire.
    Ce n'est pas tout à fait correct. C'est certes une solution, mais certains compilateur gère mal l'inclusion de ce genre de "header", et ton .exe peut avoir une taille assez importante.

    Il existe une autre solution qui est, dans ton cas, d'ajouter cette ligne dans ton designpatterns.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    template class Singleton<MainWindow>;
    C'est pas forcément très générique, mais c'est un autre moyen de faire, et aussi de limiter l'utilisation du pattern.

    G.
    Un problème avec Qt ? Vous trouverez votre réponse ici : http://doc.trolltech.com/4.6/overviews.html
    En français (traduction réalisée par l'équipe Qt de DVP) : http://qt.developpez.com/doc/4.6/vues-d-ensemble/

  4. #4
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Gulish Voir le message
    Ce n'est pas tout à fait correct. C'est certes une solution, mais certains compilateur gère mal l'inclusion de ce genre de "header", et ton .exe peut avoir une taille assez importante.

    Il existe une autre solution qui est, dans ton cas, d'ajouter cette ligne dans ton designpatterns.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    template class Singleton<MainWindow>;
    C'est pas forcément très générique, mais c'est un autre moyen de faire, et aussi de limiter l'utilisation du pattern.

    G.
    Ca réduit quand même fortement l'intérêt d'un header contenant une définition template - ce n'est même plus histoire d'être générique, c'est une question de bon sens : pourquoi écrire du code template compliqué si c'est pour ne pas l'utiliser autrement que dans un cas unique ?

    Pour ma part, et sans revenir sur mon appréciation singulière des singletons (dont, après des années de pratique, je ne vois toujours pas l'utilité), je préconise de NE PAS écrire de singleton en se basant sur un template. Le code entourant un singleton est minuscule (en C++ : guère plus d'une petite dizaine de ligne). L'intérêt de passer par une classe template est très modéré, d'autant que l'écriture de celle-ci est complexe.

    Ensuite, on pourra discourir de l'utilité d'une méthode Kill(). Un singleton est censé être valide pendant toute l'exécution du programme. Certes, cela signifie qu'il y aura, à la fin, quelques octets qui ne sont pas désaloués par l'application. Ne pas confondre ça avec une fuite de mémoire, puisque c'est sa raison d'être - et que l'OS va la récupérer de toute façon. Kill() est au mieux une méthode dangereuse - puisque le singleton peut tenir des ressources importantes qui peuvent être référencées par d'autres objets.

    Bon, ensuite, sincèrement, c'est quoi l'idée d'une fenêtre principale qui devrait être accessible de partout ? Ca n'a pas vraiment de sens selon moi... Mais là, on est plus coté design que coté code.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par secksy Voir le message
    L'erreur qui s'affiche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    debug/main.o(.text+0x16a): In function `Z5qMainiPPc':
    C:/dev/HighStory/main.cpp:11: undefined reference to `Singleton<MainWindow>::Get()'
    debug/sockethandler.o(.text+0x4f5): In function `ZN13SocketHandler3lolEv':
    C:/dev/HighStory/sockethandler.cpp:16: undefined reference to `Singleton<MainWindow>::Get()'
    La réponse est dans la F.A.Q. Pourquoi mes templates ne sont-ils pas reconnus à l'édition des liens ?

    Citation Envoyé par Emmanuel Deloget Voir le message
    Pour ma part, et sans revenir sur mon appréciation singulière des singletons (dont, après des années de pratique, je ne vois toujours pas l'utilité)
    J'ai le sentiment que souvent on utilise le singleton en se disant : je n'ai pas des variables globales car on m'a appris que c'est mal ... mais j'ai des singletons car c'est bien c'est un D.P. Alors qu'in fine, ce sont plus ou moins les mêmes problèmes.
    Lorsque j'utilise le DP singleton, c'est plus souvent voisin d'un 'entrepôt' pour garantir l'accès à une instance d'une interface abstraite montée concrètement par ailleurs plus que pour la nécessité d'avoir qu'une instance de la classe.

Discussions similaires

  1. Déserialisation et design pattern 'Singleton'
    Par tomnk dans le forum Persistance des données
    Réponses: 1
    Dernier message: 13/04/2009, 15h24
  2. scope application et design pattern singleton
    Par totoche dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 01/10/2008, 15h56
  3. [Singleton] Classe static ou Design Pattern Singleton ?
    Par piloupy dans le forum Design Patterns
    Réponses: 15
    Dernier message: 01/08/2008, 16h04
  4. Réponses: 1
    Dernier message: 04/07/2008, 14h53
  5. Implémentation du design pattern singleton
    Par 0pierrot0 dans le forum C++
    Réponses: 1
    Dernier message: 22/01/2008, 10h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo