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

C++ Discussion :

Gestion lecteurs de cartes bancaires


Sujet :

C++

  1. #1
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut Gestion lecteurs de cartes bancaires
    Bonjour,

    Je viens demander un conseil pour savoir quel est selon vous le meilleur moyen d'implémenter mon projet qui permet de gérer plusieurs types de cartes bancaires.

    J'ai 2 types de lecteurs de cartes bancaires:
    - Wynid
    - Banksys-Xenteo

    J'ai donc une classe mère CCardReader qui sert d'interface, et 2 classes filles qui implémentent cette dernière, CWynidCardReader et CBanksysXenteoCardReader.

    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
     
    class CCardReader  
    {
    public:
    	CCardReader();
    	virtual ~CCardReader();
     
    	// Opérations
    	virtual int Connect() const = 0;
    	virtual int Initialize() const = 0;
    	virtual int OpenSession() const = 0;
    	virtual int ProcessTransaction() const = 0;
    	virtual int CloseSession() const = 0;
    	virtual int Disconnect() const = 0;
     
    	virtual TCHAR* GetName() const = 0;
    };
     
    class CWynidCardReader : public CCardReader { /* Lecteur de carte Wynid */ };
     
    class CBanksysXenteoCardReader: public CCardReader { /* Lecteur de carte Banksys-Xenteo */ };
    Dans mon application MFC, j'ai un menu déroule me demandant de choisir l'un de ces lecteurs. Je dois donc créer une instance de lecteur de cartes bancaires de manière dynamique via l'opérateur new() vu que le programme ne connait le type de lecteur qu'une fois le programme exécuté.

    Ce qui donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class CTestCardReaderDlg : public CDialog
    {
    // ...
     
    private:
    	CCardReader* m_lpCardReader;
    };
    Pour rendre l'application plus résistante, j'utile l'idiome RAII sur la classe CCardReader.

    Ce qui donne:

    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
    class CCardReaderRAII  
    {
    public:
    	CCardReaderRAII(CCardReader* lpCardReader = NULL);
    	~CCardReaderRAII();
     
    	// Attache/Détache un CCardReader
    	void Attach(CCardReader* lpCardReader);
    	// Pas nécessaire car fait par le destructeur
    	void Detach();
     
    	// Opérations
    	int Connect() const;
    	int Initialize() const;
    	int OpenSession() const;
    	int ProcessTransaction() const;
    	int CloseSession() const;
    	int Disconnect() const;
     
    	TCHAR* GetName() const;
     
    private:
    	CCardReader* m_lpCardReader;
    };
     
     
    class CTestCardReaderDlg : public CDialog
    {
    // ...
     
    private:
    	CCardReaderRAII m_cardReaderRAII;
    };
     
    // Détermine le type de lecteur de carte
    switch (nIndex)
    {
    	case WYNID:
    		m_cardReaderRAII.Attach(new CWynidCardReader);
    		return TRUE;
     
    	case BANKSYS_XENTEO:
    		m_cardReaderRAII.Attach(new CBanksysXenteoCardReader);
    		return TRUE;
     
    	default: /* CB_ERR */
    		return FALSE;
    }
    J'aimerais également appliquer le RAII pour les fonctions de connexion (déconnexion automatique), d'ouverture de session (fermeture de session automatique) afin de prévenir une éventuelle erreur.

    Quel serait le meilleur moyen? Refaire une classe RAII pour ces fonctions afin de gérer ça dans le constructeur et destructeur? Comment procéder?
    Y aurait-il une autre approche qui serait meilleure?

    Merci d'avance

  2. #2
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Je vais m'inspirer de cette partie de la FAQ => http://cpp.developpez.com/faq/cpp/?p...POINTEURS_raii

  3. #3
    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
    Salut,
    A priori, de ce que je comprend tu as 2 ressources à gérer : le pointeur et la connexion de la carte. Donc tu devrais avoir 2 classes distinctes pour gérer chacune de ces ressources : un pointeur intelligent pour le pointeur et un CCardReaderRAII pour gérer la connexion. Non ?

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Si j'ai bien compris (et, si je pose la question, c'est pour te permettre de me contredire ), il n'y aura jamais, à un insant T, qu'un seul type de lecteur branché

    Une question intelligente à laquelle tu risque d'avoir du mal à répondre serait "envisages-tu que les type de lecteurs de cartes soit appelés à se multiplier dans un futur suffisamment proche que pour ta version de l'application doive encore être en mesure d'évoluer de ce coté

    Si je prévois quelques difficultés pour apporter la réponse à cette question, c'est parce que j'ai bien conscience qu'il n'y a sans doute pas des nouveaux types de lecteurs de cartes qui apparaissent tous les jours...

    Par contre, ce dont je suis sur, c'est que, au rythme auquel évolue la technique, il est difficile de prévoir de quoi demain sera fait (quel sera l'état de la technique d'ici 2 ou 3 ans ou ... 10)...

    Si la réponse à ces deux questions venait à être "oui", je te conseillerais volontiers de sortir "la grosse artillerie", avec fabrique, éventuellement prototypes, manager potentiellement sous la forme de singleton , et tout l'toutim...

    L'idée étant de faciliter au maximum les évolutions futures: lorsqu'un nouveau type de lecteur de cartes apparait, tu le fait dériver de CCardReader, tu l'inscrit dans la fabrique, tu le rajoute dans le menu déroulant de l'interface graphique, et merci bonsoir: un petit coup de compilation et le tour est joué

    (bon, je l'admets, c'est la version "optimiste )

    Si tu estimes que l'évolution arrivera bien après la durée de vie de ton application, un truc beaucoup plus simple peut suffir:

    un "CardReaderManager, auquel tu demande de créer et de détruire les instances réelles descendant de CCardReader et avec lequel communique ton IHM
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Effectivement, je pourrais utiliser un pointeur intelligent (std::auto_ptr) pour gérer le pointeur sur CCardReader à la place de créer une classe CCardReaderRAII qui fait le même travail.

    Il me reste 2 ressources à gérer:
    - La connexion/déconnexion
    - L'ouverture/fermeture de session

    Pour ces 2 ressources, je pense qu'il faut faire une classe RAII.

  6. #6
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,

    Si j'ai bien compris (et, si je pose la question, c'est pour te permettre de me contredire ), il n'y aura jamais, à un insant T, qu'un seul type de lecteur branché
    Effectivement, un seul à la fois


    Citation Envoyé par koala01 Voir le message
    Une question intelligente à laquelle tu risque d'avoir du mal à répondre serait "envisages-tu que les type de lecteurs de cartes soit appelés à se multiplier dans un futur suffisamment proche que pour ta version de l'application doive encore être en mesure d'évoluer de ce coté

    Si je prévois quelques difficultés pour apporter la réponse à cette question, c'est parce que j'ai bien conscience qu'il n'y a sans doute pas des nouveaux types de lecteurs de cartes qui apparaissent tous les jours...

    Par contre, ce dont je suis sur, c'est que, au rythme auquel évolue la technique, il est difficile de prévoir de quoi demain sera fait (quel sera l'état de la technique d'ici 2 ou 3 ans ou ... 10)...

    Si la réponse à ces deux questions venait à être "oui", je te conseillerais volontiers de sortir "la grosse artillerie", avec fabrique, éventuellement prototypes, manager potentiellement sous la forme de singleton , et tout l'toutim...

    L'idée étant de faciliter au maximum les évolutions futures: lorsqu'un nouveau type de lecteur de cartes apparait, tu le fait dériver de CCardReader, tu l'inscrit dans la fabrique, tu le rajoute dans le menu déroulant de l'interface graphique, et merci bonsoir: un petit coup de compilation et le tour est joué

    (bon, je l'admets, c'est la version "optimiste )

    Si tu estimes que l'évolution arrivera bien après la durée de vie de ton application, un truc beaucoup plus simple peut suffir:

    un "CardReaderManager, auquel tu demande de créer et de détruire les instances réelles descendant de CCardReader et avec lequel communique ton IHM

    Justement, le lecteur belge vient de changer. Avant c'était Banksys, et maintenant c'est Banksys-Xenteo. De plus, je pense qu'en Espagne et Italie, on utilise encore un autre type de lecteur. Donc je dirais qu'il est plus qu'envisageable que de nouveaux lecteurs apparaissent.

    Je vais donc regarder du côté de la fabrique. Il est tant d'utiliser des design patterns.

    Toutefois, j'aimerais juste savoir comment gérer les 2 ressources cités au dessus. En créant une classe où j'utilise la ressource dans le constructeur et la libère dans le destructeur selon l'idiome RAII?

  7. #7
    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 Trunks Voir le message
    Effectivement, je pourrais utiliser un pointeur intelligent (std::auto_ptr) pour gérer le pointeur sur CCardReader à la place de créer une classe CCardReaderRAII qui fait le même travail.

    Il me reste 2 ressources à gérer:
    - La connexion/déconnexion
    - L'ouverture/fermeture de session

    Pour ces 2 ressources, je pense qu'il faut faire une classe RAII.
    Normalement, chaque classe RAII ne gère qu'une seule ressource. Donc, il t'en faudrait 2. Mais en même temps, ta session doit être contenue dans ta connexion. ?

  8. #8
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Normalement, chaque classe RAII ne gère qu'une seule ressource. Donc, il t'en faudrait 2. Mais en même temps, ta session doit être contenue dans ta connexion. ?
    J'utilise une DLL externe qui a des fonctions distinctes:
    - connexion()
    - initialisation()
    - ouverture_session()
    - fermeture_session()
    - deconnexion()

    Je fais appel à ces fonctions que j'encapsule dans une nouvelle interface afin de mieux gérer les ressources.
    Bien sûr, chaque lecteur de carte a sa propre implémentation. D'où je pense qu'il faut gérer 2 ressources, chaque fonction étant susceptible de planter.

  9. #9
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Pourquoi ne pas implémenter le state pattern ?

    De cette manière, tu aurais un pointeur sur un ICardReaderState qui serait initialisé à un état de lecteur (un objet instanciable dérivé de l'interface ICardReaderState) via une certaine méthode dans une classe CCardReaderManager et qui s'occuperait de faire l'initialisation, l'appel etc à ton lecteur de carte.

    Exemple:

    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    class ICardReaderState
    {
    public:
    	ICardReaderState();
    	virtual ~ICardReaderState();
     
    	// Opérations
    	virtual int Connect() const = 0;
    	virtual int Initialize() const = 0;
    	virtual int OpenSession() const = 0;
    	virtual int ProcessTransaction() const = 0;
    	virtual int CloseSession() const = 0;
    	virtual int Disconnect() const = 0;
     
    	//virtual std::string GetName() const = 0;
    };
     
    class CWynidCardReader : public ICardReaderState
    {
    public:
    	CWynidCardReader();
    	~CWynidCardReader();
     
    	int Connect() const;
    	int Initialize() const;
    	int OpenSession() const;
    	int ProcessTransaction() const;
    	int CloseSession() const;
    	int Disconnect() const;
    };
     
    class CBanskysXenteoCardReader : public ICardReaderState
    {
    public:
    	CBanskysXenteoCardReader();
    	~CBanskysXenteoCardReader();
     
    	int Connect() const;
    	int Initialize() const;
    	int OpenSession() const;
    	int ProcessTransaction() const;
    	int CloseSession() const;
    	int Disconnect() const;
    };
     
    enum ReaderType
    {
    	WYNID,
    	BANKSYSXENTEO
    };
     
    class CCardReaderManager
    {
    	ICardReaderState *m_CardReaderState;
     
    	void SelectType( const ReaderType type );
     
    public:
    	CCardReaderManager( const ReaderType type );
    	~CCardReaderManager();
     
    	void ChangeReaderType( const ReaderType type );
     
    	// Opérations
    	int Connect() const;
    	int Initialize() const;
    	int OpenSession() const;
    	int ProcessTransaction() const;
    	int CloseSession() const;
    	int Disconnect() const;
    };
     
    CCardReaderManager::CCardReaderManager( const ReaderType type )
    {
    	m_CardReaderState = 0;
    	SelectType( type );
    }
     
    void CCardReaderManager::SelectType( const ReaderType type )
    {
        if( m_CardReaderState != 0 )
            m_CardReaderState->Disconnect();
     
    	delete m_CardReaderState;
     
    	switch( type )
    	{
    		case WYNID:
    			m_CardReaderState = new CWynidCardReader();
    		break;
    		case BANKSYSXENTEO:
    			m_CardReaderState = new CBanskysXenteoCardReader();
    		break;
    	}
    }
     
    CCardReaderManager::~CCardReaderManager()
    {
        if( m_CardReaderState != 0 )
            m_CardReaderState->Disconnect(); // peut-être inutile
     
    	delete m_CardReaderState;
    }
     
    void CCardReaderManager::ChangeReaderType( const ReaderType type )
    {
    	SelectType( type );
    }
    C'est juste une idée, qui peut-être ne convient pas du tout :p

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    A vrai dire, je verrais bien une arborescence proche de
    • CCardManager seul (éventuellement basé sur le singleton et le fait qu'il présente les moyens de sélectionner le lecteur ad-hoc)
    • CCardReaderFactory: la fabrique de lecteurs de cartes, non dérivée (singleton "itou")
    • CCardReader: interface de base des différents lecteurs envisageable, dérivé en autant de lecteurs que nécessaire
    • CConnection: interface de base (abstraite) des différentes connexions, dérivé en autant de connexions que nécessaire
    • CSession : interface de base (abstraite) des différentes sessions, dérivé en autant de sessions que nécessaire

    (le tout prenant en compte le fait que chaque lecteur de carte est susceptible de nécessiter sa propre connexion et sa propre session)

    Chaque lecteur de carte réel (autrement dit, chaque dérivé de CCardReader) gère (par agrégation) la connexion réelle et la session réelle qui lui convient

    Il les crée dynamiquement respectivement dans connexion() et ouverture_session() et les détruit respectivement (si le pointeur correspondant n'est pas nul) dans deconnexion() et fermeture_session().

    deconnexion() et fermeture_session() son "no throw"

    Le destructeur des lecteur de cartes réels appelle ces deux fonctions.

    A chaque étape (sauf dans le destructeur, mais comme deconnexion() et fermeture_session() ne lancent pas d'exception, ca marche très bien ), tu ne gère dynamiquement qu'une seule ressource, ce qui te permet de rester "exception safe"

    Les sessions et des connexions réelles sont adaptées pour être "defaut constructibles" et présentent une interface permettant de passer chaque paramètre séparément
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Merci pour vos idées, je ne connais pas bien les design patterns. Je connaissais à peu près le principe de ces design, mais je ne suis pas encore assez à l'aise pour savoir lesquels utiliser dans telles scénarios.
    Je jette un œil à vos 2 propositions;


  12. #12
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    Pourquoi ne pas implémenter le state pattern ?

    De cette manière, tu aurais un pointeur sur un ICardReaderState qui serait initialisé à un état de lecteur (un objet instanciable dérivé de l'interface ICardReaderState) via une certaine méthode dans une classe CCardReaderManager et qui s'occuperait de faire l'initialisation, l'appel etc à ton lecteur de carte.

    Exemple:

    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    class ICardReaderState
    {
    public:
    	ICardReaderState();
    	virtual ~ICardReaderState();
     
    	// Opérations
    	virtual int Connect() const = 0;
    	virtual int Initialize() const = 0;
    	virtual int OpenSession() const = 0;
    	virtual int ProcessTransaction() const = 0;
    	virtual int CloseSession() const = 0;
    	virtual int Disconnect() const = 0;
     
    	//virtual std::string GetName() const = 0;
    };
     
    class CWynidCardReader : public ICardReaderState
    {
    public:
    	CWynidCardReader();
    	~CWynidCardReader();
     
    	int Connect() const;
    	int Initialize() const;
    	int OpenSession() const;
    	int ProcessTransaction() const;
    	int CloseSession() const;
    	int Disconnect() const;
    };
     
    class CBanskysXenteoCardReader : public ICardReaderState
    {
    public:
    	CBanskysXenteoCardReader();
    	~CBanskysXenteoCardReader();
     
    	int Connect() const;
    	int Initialize() const;
    	int OpenSession() const;
    	int ProcessTransaction() const;
    	int CloseSession() const;
    	int Disconnect() const;
    };
     
    enum ReaderType
    {
    	WYNID,
    	BANKSYSXENTEO
    };
     
    class CCardReaderManager
    {
    	ICardReaderState *m_CardReaderState;
     
    	void SelectType( const ReaderType type );
     
    public:
    	CCardReaderManager( const ReaderType type );
    	~CCardReaderManager();
     
    	void ChangeReaderType( const ReaderType type );
     
    	// Opérations
    	int Connect() const;
    	int Initialize() const;
    	int OpenSession() const;
    	int ProcessTransaction() const;
    	int CloseSession() const;
    	int Disconnect() const;
    };
     
    CCardReaderManager::CCardReaderManager( const ReaderType type )
    {
    	m_CardReaderState = 0;
    	SelectType( type );
    }
     
    void CCardReaderManager::SelectType( const ReaderType type )
    {
        if( m_CardReaderState != 0 )
            m_CardReaderState->Disconnect();
     
    	delete m_CardReaderState;
     
    	switch( type )
    	{
    		case WYNID:
    			m_CardReaderState = new CWynidCardReader();
    		break;
    		case BANKSYSXENTEO:
    			m_CardReaderState = new CBanskysXenteoCardReader();
    		break;
    	}
    }
     
    CCardReaderManager::~CCardReaderManager()
    {
        if( m_CardReaderState != 0 )
            m_CardReaderState->Disconnect(); // peut-être inutile
     
    	delete m_CardReaderState;
    }
     
    void CCardReaderManager::ChangeReaderType( const ReaderType type )
    {
    	SelectType( type );
    }
    C'est juste une idée, qui peut-être ne convient pas du tout :p
    Mon implémentation actuelle est très proche de ce design pattern. Sauf que ce design est mieux organisé que mon code et les nom sont plus explicites Ca pourrait convenir à mes besoins.

    Maintenant j'étudie la proposition de koala01 pour voir si son approche correspond mieux ou non.

    En tout cas je suis content d'avoir posté ici, ça me permet d'utiliser des design patterns précis et ainsi faire une application bien plus propre

  13. #13
    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
    Bonjour,
    J'ai peut être une approche un peu trop rigide, mais l'exemple de Julien n'est pas pour moi un pattern Etat (cf ici).
    Le pattern Etat est certainement pertinent mais pour modéliser l'état de ta connexion (donc certainement dans CCardReader)...pas pour modéliser le choix d'un type de carte ou d'un autre. Je préfère l'approche de Koala.

  14. #14
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Avant tout, qu'est-ce-qu'un singleton "itou"?

    J'ai étudié minutieusement vos 2 propositions.

    Le design pattern state gère un objet à la fois tandis que le design pattern factory gère une multitude d'objets en même temps.

    Dans mon exemple concret, je ne gère que d'un lecteur de carte à la fois. Soit je travaille avec un lecteur de type Wynid (France), soit je travaille avec un lecteur de type Banksys-Xenteo (Belgique), plus éventuellement ceux de l'Espagne et de l'Italie plus tard.

    En fait, il me manquait juste la notion de manager qui fait appel à la fermeture de session et à la fermeture de connexion dans son destructeur. Ainsi, si une erreur se produit dans l'application, les ressources seront bel et bien libérés ce qui respecte le principe du RAII.

    Le code présenté par JulienDuSud correspond pas mal à ce que je souhaite même si les types de lecteurs de cartes ne sont pas vraiment des états, donc on ne peut pas vraiment l'appeler pattern state. Mais le principe reste le même. L'approche présenté par koala01, selon moi, est disproportionné par rapport à mon application. Pas la peine d'aller aussi loin vu que je ne gère qu'un lecteur à la fois et non pas plusieurs.


    Une fois de plus merci pour votre solution qui me seront très utiles pour la suite!


  15. #15
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Pour te donner une idée du DP factory, cela pourrait ressembler, dans ton cas à:
    fichier CCardReaderFacory.hpp
    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
    #ifndef CCardReaderFacory.hpp
    #define CCardReaderFacory.hpp
    #include <string>
    #include <map>
    class CardReader;
     
    class CCardReaderFactory
    {
    /* juste pour la facilité, mais à usage interne */
    typedef std::map<std::string, CCardReader*> readermap;
    typedef readermap::iterator iterator;
        public:
            /*ce doit être un singleton  */
            static CCardReaderFactory& instance()
            {
                static CCardReaderFactory obj;
                return obj;
            }
            CCardReader* create(std::string const&) const;
        private:
            readermap items;
            CCardReaderFactory();
            ~CCardReaderFActory();
            /* déclaration des constructeur par copie, mais pas de définition */
            CCardReaderFActory(CCardReaderFActory const&);
            CCardReaderFActory& operator = (CCardReaderFActory const&);
    }
    fichier CCardReaderFacory.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
    #include "CCardReaderFacory.hpp"
    /* il faut connaitre tous les lecteurs de cartes */
    #include "CWynidCardReader.hpp"
    #include "CBanskysXenteoCardReader.hpp"
    /*...*/
     
    /*L'enregistrement des lecteurs de cartes se fait dans le constructeur */
    CCardReaderFacory::CCardReaderFacory()
    {
        items.insert(std::make_pair("Banskys",
                     new CBanskysXenteoCardReader()));
        items.insert(std::make_pair(("Wynid",new CWynidCardReader()));
        /*...*/
    }
    /* Lorsque l'instance est détruite, les prototypes itou */
    CCardReaderFacory::CCardReaderFacory()
    {
        for(iterator it=items.begin(); it!=items.end();++it)
            delete it->second;
    }
    CCardReader* CCardReaderFacory::create(std::string const& name)
    {
        iterator  it=items.find(name);
        if(it==items.end())
            return 0;
        return it->second->clone();
    }
    Les implications
    Dans la classe CCardReader, il faut une fonction virtuelle pure clone() const supplémentaire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class CCardReader
    {
        public:
            /*...*/
            CCardReader* clone() const = 0;
    };
    qui sera implémentée en utilisant le retour covariant dans les classes de lecteur réelle. ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class CWynidCardReader
    {
        public:
            CWynidCardReader* clone() const
            {
                return new CWynidCardReader();
            }
            /*...*/
    };
    Dans la classe CCardReaderManager, la fonction de sélection du lecteur de cartes appelée par l'IHM resemblera à:
    CCardReaderManager.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class CCardReader
    class CCardReaderManager
    {
        public:
            bool selectReader(std::string const&);
            /*...*/
        private:
            CCardReader*  reader;
    };
    CCardReaderManager.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
    #include "CCardReaderManager.hpp"
     
    /* Le manager ne doit connaitre que la fabrique et le CCardReader */
    #include "CCardReaderFacory.hpp"
    #include "CCardReader.hpp"
    /*...*/
     
    /* Tout ce que l'IHM doit savoir, c'est si ca a réussi */
    bool CCardReaderManager::selectReader(std::string const& name)
    {
        /* reader est un pointeur de type CCardReader, membre privé de la 
         * classe
         */
        delete reader;
        reader = CCardReaderFacory::instance().create(name);
        return reader!=0;
        /*EDIT Nota: tu pourrais envisager de garder l'instance du lecteur
         * en cours dans un pointeur temporaire qui ne serait détruit
         * que si la création du nouveau lecteur a fonctionné, sous une 
         * forme proche de
         * CCardReader *temp = reader;
         * reader= CCardReaderFacory::instance().create(name);
         * if(!reader)
         * {
         *     reader = temp;
         *     return false;
         * }
         * delete temp;
         * return reader!=0;
         * cela t'éviterait de détruire un lecteur actif pour... le recréer au
         * cas où le nouveau demandé n'a pas pu être créé...(si cela rentre
         * dans les specs ;) )
         */
    }
    [EDIT]Tu l'aura compris, ce code est écrit "from scratch", incomplet et non testé... mais rejoint l'objectif fixé qui était de te donner une idée de comment faire
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  16. #16
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Je te remercie, je vais m'appuyer dessus

    En fait, le système de manager correspond exactement à ce que je recherchais depuis pas mal de temps, c'est vraiment un outil pratique

  17. #17
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ouppsss...

    Je viens de me rendre compte que j'ai écrit une absurdité dans le code...

    Push_back n'existe pas dans une std::map, j'ai modifié le code pour qu'il soit correct en utilisant insert et make_pair

    Nous sommes bien d'accord sur le fait que l'exemple présenté peut être fortement modifié, par exemple, en transformant le CReaderManager en singleton, s'il apparait que tu dois y faire appel à différents endroits de l'IHM en gardant une instance unique et toujours identique

    Et, s'il apparait que, bien que ce ne soit pas l'idéal, tu te trouve dans une situation dans laquelle tu va assister à la multiplication des singletons, tu peux même envisager la création d'un modèle de singleton (pourquoi pas avec des traits de politiques) et l'utilisation du CRTP...

    Sans trait de politique, cela pourrait ressembler à
    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
    template <class T>
    class TSingleton
    {
        public:
            static T& instance()
            {
                static T obj;
                return obj;
            }
        protected: 
        /* il faut que le constructeur et le destructeur soient accessibles
         * aux classes dérivées */
            TSingleton();
            ~TSingleton();
        private:
        /* mais la copie et l'assignation sont interdites 
         * (les fonctions ne sont pas définies)
         */
        TSingleton (TSingleton const&);
        TSingleton& operator=(TSingleton const&);
    };
    Mise en oeuvre du CRTP
    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
     
    /*Ca c'est le CRTP:
     * La classe template prend, comme type réel, le type
     * qui dérive de la classe template :8
     * c'est curieusement récursif comme idée ;)
     */
    class MonSingleton: public TSingleton<MonSingleton>
    {
        /* TSingleton doit avoir acces au constructeur... */
        friend class TSingleton<MonSingleton>;
        public:
           /*les fonctions utiles d'utilisation de MonSingleton, non statiques */
        private:
            /* constructeurs et destructeurs privés, à définir */
            MonSingleton();
            ~MonSingleton();
            /* copie et assignation interdites, les fonctions restent 
             * non définies 
             */
            MonSingleton(MonSingleton const&);
            MonSingleton& operator=(MonSingleton const&);
    };
    Les traits de politique pourraient être utilisés pour adapter le singleton à des particularités telles que l'utilisation "multithread" ou non, qu'il doive ou non présenter une résistance aux références invalide, j'en passe, et de meilleures
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  18. #18
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Des réponses toujours aussi complètes et mûrement réfléchies pour être fonctionner dans la plupart des cas de figures

    On ne le dira jamais assez, mais merci à tous les posteurs du forums qui prennent le temps d'analyser les problèmes de chacun et proposer des solutions de manière si développée et faire partager vos savoirs

  19. #19
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    N'oublie pas que la qualité d'un projet dépend en grande partie de la qualité de l'analyse et de la conception...

    Par qualité, je n'entend pas seulement le fait que l'application fasse ce que l'on attend d'elle, mais aussi le fait qu'elle soit capable d'évoluer sans *trop* se casser la tête et sans nécessiter *trop* de changements en profondeur...

    Si nous arrivons à te faire comprendre les concepts / patterns mis en oeuvre cette fois ci, il y a des chances que tu y pensera "naturellement" la prochaine fois que tu sera confronté à un problème similaire...

    Ce qui t'évitera de reposer la question, et nous facilitera la vie à tous (mais d'abord à toi )

    En plus, cela te permettra de répondre toi aussi au genre de problème, si quelqu'un d'autre y est confronté: ca provoque la "transmission du savoir", qui est réellement indispensable car tout le monde aime à disposer d'application de qualité
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Amazon : bientôt un lecteur de cartes bancaires sur mobile ?
    Par Stéphane le calme dans le forum Actualités
    Réponses: 6
    Dernier message: 18/08/2014, 16h29
  2. Help lecteur de cartes T2G/bancaire avec un PIC
    Par sin92 dans le forum Embarqué
    Réponses: 1
    Dernier message: 27/05/2012, 19h12
  3. [Lecteurs de cartes]Modifier les lettres de lecteur
    Par al1_24 dans le forum Windows XP
    Réponses: 2
    Dernier message: 30/12/2005, 11h48
  4. Réponses: 1
    Dernier message: 25/11/2005, 22h30
  5. Algorithme [Gestion d'un compte bancaire]
    Par Laeticia dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 04/02/2005, 10h57

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