Partage

[EXERCICE POO] Pharmacie

Niveau débutant POO

Anonyme
15 avril 2014 à 16:40:18

Bonjour,

Je présente un exercice que j'ai travaillé en Java lors d'un MOOC. Il est adapté dans notre cas à notre langage préféré, le python...

Objectif : Ecrire un programme orienté objets qui permet de gérer une pharmacie.

La pharmacie gère des clients et des médicaments. Un client est caractérisé par un nom et un crédit. Le crédit représente la somme que ce client doit à la pharmacie. Le crédit peut être négatif si le client a versé plus d'argent que le montant. Un médicament est caractérisé par un nom (chaîne de caractères), un prix (nombre) et un stock (entier). Les méthodes à compléter auront les caractéristiques suivantes:

affichage(...) permet d'afficher les clients et leurs crédits respectifs ainsi que les médicaments et leurs stocks respectifs.

approvisionnement(..) permet d'approvisionner le stock d'un médicament. Le nom du médicament à approvisionner ainsi que la quantité à ajouter au stock doivent être lus depuis le terminal. Lorsque le nom du médicament est introduit, il faut vérifier qu'il s'agit bien d'un nom connu dans la liste des médicaments de la pharmacie. Le programme doit boucler jusqu'à introduction d'un nom correct. Cette procédure de vérification sera prise en charge par la méthode lireMedicament(..) décrite plus bas.

achat(..) permet de traiter un achat fait par un client. l'achat porte sur un médicament donné dans une quantité donnée. Pour cette transaction le client paie un certain prix. Une opération d'achat aura pour effet de déduire la quantité achetée du stock du médicaments correspondant et d'augmenter le crédit du client (d'un montant équivalent au montant de l'achat moins la somme payée).
Les noms du client et du médicament doivent être lus depuis le terminal. Le programme doit boucler jusqu'à introduction de noms connus aussi bien pour les clients que les médicament. Ces procédures de vérification seront prises en charge par les méthodes lireClient et lireMedicament (voir plus bas). La quantité achetée et le montant payé sont aussi lus depuis le terminal. Ils seront supposés corrects.

quitter(..) affiche le message "programme terminé!".

Vous définirez une méthode auxiliaire lireClient(..) prenant comme paramètre un liste de clients. Elle permettra de lire le nom d'un client depuis le terminal et de vérifier si ce client existe dans la liste des clients. Dans ce cas le client sera retourné. Cette méthode doit boucler jusqu'à ce qu'un client soit trouvé. Elle sera utilisée par la méthode achat(..). Une méthode similaire, lireMedicament(..) sera fournie pour les médicaments. Elle sera utilisée par les méthodes achat(..) et approvisionnement(..).

Vous êtes libre de définir, en plus de ces méthodes, toutes celles que vous jugerez nécessaires.

Le programme sera exécuté et donnera ce genre de résultat

1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
2
Nom du medicament?:
Aspiron
Donner la Quantite :
2


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
3
Affichage des stocks
Stock du medicament Aspiron :7
Stock du medicament Rhinoplexil :5
Affichage des credits
Credit du client Malfichu :0.0
Credit du client Palichon :0.0


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
1
Nom du client?:
Malfichu
Nom du medicament?:
Aspiron
quel est le montant du paiement?
30.0
quelle est la quantite achetee?
3


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
3
Affichage des stocks
Stock du medicament Aspiron :4
Stock du medicament Rhinoplexil :5
Affichage des credits
Credit du client Malfichu :31.199999999999996
Credit du client Palichon :0.0


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
1
Nom du client?:
Palichon
Nom du medicament?:
Aspiron
quel est le montant du paiement?
5
quelle est la quantite achetee?
5
Achat Impossible. Quantite insuffisante


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
3
Affichage des stocks
Stock du medicament Aspiron :4
Stock du medicament Rhinoplexil :5
Affichage des credits
Credit du client Malfichu :31.199999999999996
Credit du client Palichon :0.0


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
1
Nom du client?:
Palichon
Nom du medicament?:
Rhinoplexil
quel est le montant du paiement?
200
quelle est la quantite achetee?
5


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
3
Affichage des stocks
Stock du medicament Aspiron :4
Stock du medicament Rhinoplexil :0
Affichage des credits
Credit du client Malfichu :31.199999999999996
Credit du client Palichon :-104.25


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
1
Nom du client?:
Febril
Client inconnu. Veuilliez recommencer
Malfichu
Nom du medicament?:
Placebo
Medicament inconnu. Veuilliez recommencer
Aspiron
quel est le montant du paiement?
2
quelle est la quantite achetee?
1


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
3
Affichage des stocks
Stock du medicament Aspiron :3
Stock du medicament Rhinoplexil :0
Affichage des credits
Credit du client Malfichu :49.599999999999994
Credit du client Palichon :-104.25


1 : Achat de medicament
2 : Approvisionnement en  medicaments
3 : Etats des stocks et des credits
4 : Quitter
4
Programme termine!

Voici la composition simplifiée du programme principal

def menu():
    print("""1 : Achat de medicament
2 : Approvisionnement en medicaments
3 : Etats des stocks et des credits
4 : Quitter""")

    while True:
        try:
            choix = int(input("Entrez votre choix: "))
            if choix in range(1, 5):
                break
        except ValueError:
            continue

    return choix

Malfichu = Client("Malfichu",0.0)
Palichon = Client("Palichon",0.0)

Aspiron = Medicament("Aspiron", 20.40, 5)
Rhinoplexil = Medicament("Rhinoplexil", 19.15, 5)

clients = [Malfichu, Palichon]
medicaments = [Aspiron, Rhinoplexil]

while True:

    choix = menu()

    if choix == 1:
        achat(clients, medicaments)
    elif choix == 2:
        approvisionnement(medicaments)
    elif choix == 3:
        affichage(clients, medicaments)
    else:
        break

quitter()

Amusez-vous bien ;)

16 avril 2014 à 14:48:56

salut,

bonne idée, ça va me faire réviser mes notion sur les classes.

je code ça et je poste.

Bevet Breizh! Breizh dizalc'h! Betek an trec'h! Ha mallozh ruz d'ar c'hallaoued! Trouvez votre voie
18 avril 2014 à 10:53:24

dès que j'ai du temps(je suis en pleine rénovation de mon appart.) j'essaye de faire un truc propre.
Anonyme
18 avril 2014 à 11:46:44

@josmiley,

Toi faire un truc propre ? :D

L'aficionado des oneliners, je rêve, dieu doit exister...

18 avril 2014 à 12:09:01

Si j'avais du temps, je ferais bien ça sous formes de closures pour rigoler. :D

Zeste de Savoir, le site qui en a dans le citron !
Anonyme
18 avril 2014 à 13:08:34

Fais toi plaisir ;)

18 avril 2014 à 13:58:56

OK, dans ce cas, voilà comment ne pas implémenter la classe Client à moins d'être vraiment amoureux du Lisp :

ATTR = 0
STR = 1

def new(name, credit=0):
    _name = name
    _credit = credit

    def attr(x, v=None):
        nonlocal _name
        nonlocal _credit
        if x == 'name':
            if v is not None:
                _name = v
            return _name
        elif x == 'credit':
            if v is not None:
                _credit = v
            return _credit

    def to_string():
        return "Client(name=%s, credit=%0.2f)" % (_name, _credit)

    return (attr, to_string)


name = lambda self, val=None: self[ATTR]('name', val)
credit = lambda self, val=None: self[ATTR]('credit', val)
str = lambda self: self[STR]()
>>> import client
>>> c = client.new("nohar", 42)
>>> print(client.name(c))
nohar
>>> print(client.credit(c))
42
>>> client.credit(c, 54)
54
>>> print(client.credit(c))
54
>>> print(client.str(c))
Client(name=nohar, credit=54.00)

J'aurais pu le faire avec un dictionnaire plutôt que des variables séparées, mais je trouve la solution actuelle encore plus obscure. On s'amuse d'un rien. :p

-
Edité par nohar 18 avril 2014 à 14:04:51

Zeste de Savoir, le site qui en a dans le citron !
Anonyme
18 avril 2014 à 14:41:00

Ouais c'est pas mal, mais je trouve ça moins naturel, que de créer une classe. On pourrait faire cela avec les namedtuple

from collections import namedtuple

class Client(namedtuple('Client', 'name credit')):

    @property
    def __str__(self):
        return "Client(name={0}, credit={:1.2f})".format(self.name, self.credit)

c = Client("fred1599", 42)

print(c)
print(c.credit)
print(c.name)
fred1599@fred1599-Aspire-5741G:~$ python3 test.py
Client(name='fred1599', credit=42)
42
fred1599




11 mai 2014 à 19:16:15

Salut à tous,

J'ai relevé le défi.

Par contre, je sais pas c'est de la POO et si j'ai absolument respecté les consignes à 100% :)

Et je crois que c'est plein de fautes d'orthographe.

Je poste mon code ainsi que les fichier :

import random
import pickle
print("Bienvenue dans la Pharmacie de Cirdo")

#-------------------------------------------------------------------------------
#                          Class et Fonction
#-------------------------------------------------------------------------------

#Class -------------------------------------------------------------------------
class Client():
  """Client"""
  def __init__(self,credits,nom_client):
    self.credits = credits #Argent du client
    self.nom_clients = nom_client  #Nom du client



  def __str__(self):
    return "{}, tu as {} €".format(self.nom_clients,self.credits)
#Fonction ----------------------------------------------------------------------
def medoc_recupere():
  """Recupere dans un fichier les nom des médoc"""
  with open("medoc.txt","r") as fichier:
    contenu = fichier.read()
  contenu = contenu.split("\n")
  for i,elt in enumerate(contenu):
    if elt is not "":
      elt = elt.split(":")
      elt1 = elt[1].split(",")
      elt1[0] = int(elt1[0])
      elt1[1] = int(elt1[1])
      medicament[elt[0]] = elt1



def client_recpuere():
  """Recupere dans un fichier binaire les clients"""
  client = list()
  try :
    with open("client.bvm","rb") as fichier:
      my_pickle = pickle.Unpickler(fichier)
      client = my_pickle.load()
  except EOFError:
    pass
  except FileNotFoundError:
    pass
  return client


def affiche_medoc(medicaments):
  """Affiche les medoc"""
  j =0

  for i,elt in medicaments.items():
    if j is 0:
      print("Il reste {} {} à {} €,".format(elt[0],i,elt[1]))
    elif j is not 0:
      if j is (len(medicament)-1):
        print("{} {} à {} €.\n".format(elt[0],i,elt[1]))
      else:
        print("{} {} à {} €,".format(elt[0],i,elt[1]))
    j+=1

def achat_medoc(client,medoc):
  """Permet l'achat des medoc"""
  boolean_nom = False
  boolean_medoc = False
  id_client = 0
  nom = input("Votre nom de client : ")
  for i,elt in enumerate(client):
    if elt.nom_clients == nom:
        print("Client deja créer")
        boolean_nom = True
        id_client = i
  if boolean_nom is False:
    print("Création du client...")
    client.append(Client(random.randint(0,100),nom))
    print(client[len(client)-1])
    id_client = len(client)-1
  if client[id_client].credits < 0:
    print("Desolez mais vous en deficites...")
  else:
    nom_medoc = input("Nom de médicament : ")
    nb_medoc = 0
    for i,elt in medoc.items():
      if i == nom_medoc:
        boolean_medoc = True
        elt[1] = int(elt[1])
        nb_medoc = elt[1]

    if boolean_medoc is False:
      print("Nous avons pas de '{}'.".format(nom_medoc))
    else:
      try :
        nb_q_medoc =int(input("Le nombre de medicament : "))
      except ValueError:
        print("Erreur : Ce ne sont pas des chiffre")
        exit(1)
      if nb_q_medoc > medicament[nom_medoc][0]:
        print("Il n'y a plus asser de {}".format(nom_medoc))
      elif nb_q_medoc*nb_medoc > client[id_client].credits:
        print("Impossible d'effectuer l'achat, il est tros chère")
      else:
        print("Montant du Médicament : {}".format(nb_medoc))
        print("Montant total : {} €".format((nb_q_medoc*nb_medoc)))
        medicament[nom_medoc][0] -=nb_q_medoc
        client[id_client].credits -= (nb_q_medoc*nb_medoc)
        print(client[id_client],"\n")


def appro(medoc):
  """permet d'approviosement"""
  nom_medoc = input("Nom de médicament : ")
  nb_medoc = 0
  boolean_medoc = False

  for i,elt in medoc.items():
    if i == nom_medoc:
      boolean_medoc = True

      elt1 = int(elt[1])
      nb_medoc = elt1
      print(nb_medoc)



  if boolean_medoc is False:
    print("Rajout du médicaments : {}".format(nom_medoc))
    medoc[nom_medoc] = int(input("Le prix du nouveau médicaments :  "))

  else:
    try :
      nb_q_medoc =int(input("Le nombre de medicament : "))
    except ValueError:
      print("Erreur : Ce ne sont pas des chiffre")
      exit(1)
  medicament[nom_medoc][0] +=nb_q_medoc

def enregistrement_medoc(medoc):
  """Fonction qui enregistre les nom des medoc"""
  with open("medoc.txt","w") as fichier:
    for i,elt in medoc.items():
      write_contenu = "{}:{},{}\n".format(i,elt[0],elt[1])
      fichier.write(write_contenu)
def enristrement_client(client):
  """Enrigistre les clients en binaire"""
  with open("client.bvm","wb") as fichier:
    my_pickle = pickle.Pickler(fichier)
    my_pickle.dump(client)
#-------------------------------------------------------------------------------
#                          Programme Principale
#-------------------------------------------------------------------------------

client = list() #Liste de tous les clients

medicament = dict()
medoc_recupere()
client = client_recpuere()
while 1:
  print("Que vous les vous faire ????")
  choix = input("1 : Achat de medicament\n\
2 : Approvisionnement en  medicaments\n\
3 : Etats des stocks et des credits\n\
4 : Quitter\n")

  try :
      choix = int(choix)
  except ValueError:
    print("Erreur : La valeur n'est pas un chiffre")
  if choix is 3:
    affiche_medoc(medicament)
  elif choix is 1:
    achat_medoc(client,medicament)
  elif choix is 2:
    appro(medicament)
  elif choix is 4:
    print("Enregistrement des paramettres...")
    enregistrement_medoc(medicament)
    enristrement_client(client)
    break

print("Aurevoir dans la Pharmacie de Cirdo")

Fichier :

Cyborg:1,1000000
Aspirine:1,3
Dentifrice:3,2
Cachet:15,2
Prothèse:8,17
Platre:2,25
Preservatif:1,1


Dite moi ce que vous en pensé ?

-
Edité par Cirdo 11 mai 2014 à 19:17:32

Anonyme
12 mai 2014 à 11:19:22

"si j'ai absolument respecté les consignes à 100%"

Eh bien non :(

Surtout pour les débutants en POO, il est toujours conseillé de suivre une démarche afin de vous guider le mieux possible.

Je testerais ton code plus en détails...

12 mai 2014 à 17:34:59

En gros j'ai fait du hors-sujet.

fred1599 a écrit:

          Il est toujours conseillé de suivre une démarche afin de vous guider le mieux possible.

Alors quel démarche me conseillerais-tu ??? 

Anonyme
12 mai 2014 à 17:46:37

"Alors quel démarche me conseillerais-tu ???"

Euh... Tout est écrit dans le 1er post et détaillé, je peux rien te dire de plus. Maintenant si tu veux des détails sur les méthodes présentées parce-que tu ne les comprends pas (exemple je comprend pas affichage, approvisionnement, ...), pas de soucis, je t'explique !

12 mai 2014 à 18:39:55

En gros, on fait une class Pharmacie qui gère des class Medicament, des class Client ?
Anonyme
12 mai 2014 à 19:05:08

Tout à fait !

medicaments est une liste des médicaments de la pharmacie, donc pas une classe...

Mais à la rigueur, tu peux gérer les clients dans une liste ou un dictionnaire au choix, la seule chose qu'on t'impose est de respecter les méthodes indiquées dans le 1er post, ça demande tout de même un minimum de réflexion, je te conseille de prendre ton temps ;)

-
Edité par Anonyme 12 mai 2014 à 19:12:14

12 mai 2014 à 19:47:48

D'accord, merci de m'avoir éclairé :)

-
Edité par Cirdo 12 mai 2014 à 20:49:02

20 mai 2014 à 13:59:59

@Fred

Qu'entends-tu par méthode auxiliaire? Est-ce une méthode interne à une autre méthode?

Précepte: Le mieux est l'ennemi du bien
Anonyme
20 mai 2014 à 17:43:39

"Qu'entends-tu par méthode auxiliaire? Est-ce une méthode interne à une autre méthode?"

C'est une méthode qui sera utilisée dans une autre méthode. On devra vérifier que le client existe pour faire des achats de médicaments.

20 mai 2014 à 21:33:55

Voici mon code, avec gestion des erreurs:

#Programme valide en python 3.4


class Pharmacie:

    def __init__(self):
        """
        Dictionnaire des clients et de leur crédit.
        Dictionnaire des médicaments et de leur quantité et prix"""

        self.clients = {"Antorce": 0.0, "Fraktuur": 0.0, "Khontuzion": 0.0}
        self.medicaments = {"Ogardavou": [530, 12.99], "Constipax": [93, 3.85]}


    def menuPrincipal(self):
        """Menu principal"""

        #Le choix de l'utilisateur va activer la méthode adéquate
        equivalence_menu = (self.achat, self.approvisionnement,
        self.affichage, self.menuPrincipal, self.quitter)

        #Affiche le menu
        print("")
        print("0. Achat de médicament")
        print("1. Approvisionnement en médicaments")
        print("2. Etats des stocks et des crédits")
        print("3. Menu principal")
        print("4. Quitter")
        print("")

        erreur = True
        while erreur:
            try:
                choix = int(input("Que voulez-vous faire?: "))
                #Le choix doit correspondre à l'un des indices de
                #la variable equivalence_menu. On renvoie la méthode associée
                if choix in range(5):
                    return equivalence_menu[choix]()
            except:
                print("Entrée non valide")


    def achat(self):
        """Achat de médicament"""


        def validation_quantite(med):

            erreur = True
            while erreur:
                choix = input("En quel quantité: ")
                #Si la quantité n'est composé que de nombre
                if choix.isdigit():
                    #Si la quantité est supérieur au stock
                    if int(choix) > self.medicaments[med][0]:
                        print("Nombre supérieur au stock disponible")
                    else:
                        return int(choix)
                else:
                     print("Mauvaise syntaxe")


        def validation_monnaie(cli, med, quant):

            erreur = True
            #Calcul du montant que devra le client
            montant = quant*self.medicaments[med][1]
            print("Montant de: {}€".format(montant))

            while erreur:
                choix = input("Montant payée par {}: ".format(cli))
                try:
                    #Si le montant payé par le client est convertible
                    #en nombre flottant, alors on renvoie le montant payé et
                    #le montant total
                    if float(choix) >= 0:
                        return float(choix), montant
                except:
                        print("Entrer un montant valide")


        #Choix du client, du médicament et de la quantité
        client = self.lireClient(self.clients)
        medicament = self.lireMedicament(self.medicaments)
        quantite = validation_quantite(medicament)
        #calcul du montant total et celui payé par le client
        monnaie, montant = validation_monnaie(client, medicament, quantite)

        #Mise à jour des quantité de médicament et du crédit du client
        self.clients[client] += montant - monnaie
        self.medicaments[medicament][0] -= quantite

        print("Merci. Le crédit de {} dans la pharmacie est {:.2f}€".format(
        client, self.clients[client]))

        self.menuPrincipal()


    def approvisionnement(self):
        """Approvisionne un médicament"""


        def validation_quantite(med):

            erreur = True
            while erreur:
                choix = input("En quel quantité: ")
                #Si la quantité n'est composé que de nombre
                if choix.isdigit():
                    return int(choix)
                else:
                     print("Mauvaise syntaxe")

        #Choix du médicament et de la quantité
        medicament = self.lireMedicament(self.medicaments)
        quantite = validation_quantite(medicament)

        #Mise à jour de la quantité du médicament
        self.medicaments[medicament][0] += quantite
        print("Il y a maintenant {} {} disponible dans la pharmacie".format(
        self.medicaments[medicament][0], medicament))

        self.menuPrincipal()


    def affichage(self):
        """
        Affiche les clients connus et leur crédit
        Affiche les médicaments connus et leur quantité"""

        print("")
        print("{:14}{}".format("Client", "Crédit"))
        print("-"*20)
        for client in self.clients.items():
            print("{:14}{:>5.2f}".format(*client))

        print("")
        print("{:14}{}".format("Médicament", "Quantité"))
        print("-"*22)
        for medicament in self.medicaments.items():
            print("{0:14}{1[0]:>5}".format(*medicament))

        self.menuPrincipal()


    def quitter(self):
        """Quitter"""

        print("-"*21)
        print("| Programme terminé |")
        print("-"*21)


    def lireClient(self, liste):

        erreur = True
        while erreur:
            choix = input("Nom du client: ")

            #Si le client est dans la liste, on renvoie le client
            if choix in liste:
                return choix


    def lireMedicament(self, liste):

        erreur = True
        while erreur:
            choix = input("Nom du médicament: ")

            #Si le médicament est dans la liste, on renvoie le médicament
            if choix in liste:
                return choix



if __name__ == "__main__":
    p = Pharmacie()
    p.menuPrincipal()

Au départ pour la gestion des erreurs j'avais utilisé la récursivité mais j'ai rencontré beaucoup de problème. C'est là où je me suis rendu compte que c'est un concept très pointu, et qu'il faut bien comprendre ce qui se passe à chaque étape. Que penses-tu de la récursivité?

Pourrais-tu également me dire ce que tu penses de mon code

Edit: j'édite mon code et retire les erreur = False dans les boucles while, car apparemment le return suffit à casser la boucle.

-
Edité par Olygrim 20 mai 2014 à 23:09:51

Précepte: Le mieux est l'ennemi du bien
Anonyme
21 mai 2014 à 8:41:04

"Pourrais-tu également me dire ce que tu penses de mon code"

Dès que j'ai du temps, je regarde, merci pour la participation...

21 mai 2014 à 10:17:22

Pourrais-tu également me dire ce que tu penses de mon code

Tout est dans une seule classe. Ce n'est pas de la POO.

Zeste de Savoir, le site qui en a dans le citron !
21 mai 2014 à 10:33:09

nohar a écrit:

Tout est dans une seule classe. Ce n'est pas de la POO.

Cette phrase tu devrais l'encadrer parce que grâce à elle je commence à comprendre ce que tu appelles POO. Faire des classes ce n'est pas faire de la POO. La POO serait plus une façon d'organiser son programme, quelque chose de plus abstrait que juste la création d'une classe?



Précepte: Le mieux est l'ennemi du bien
Anonyme
21 mai 2014 à 10:36:05

Pourquoi chercher compliqué ?  C'est un travail dirigé... On voit les différentes classes apparaître dans l'énoncé, non?

La pharmacie gère des clients et des médicaments. Un client est caractérisé par un nom et un crédit. Le crédit représente la somme que ce client doit à la pharmacie. Le crédit peut être négatif si le client a versé plus d'argent que le montant. Un médicament est caractérisé par un nom (chaîne de caractères), un prix (nombre) et un stock (entier).

Pour aider un peu plus, on voit que la pharmacie va gérer des listes (clients + médicaments).

EDIT: Voir mon programme principal qui je trouve est assez simple pour être suffisamment explicite.

-
Edité par Anonyme 21 mai 2014 à 10:37:51

21 mai 2014 à 10:51:06

Cette phrase tu devrais l'encadrer parce que grâce à elle je commence à comprendre ce que tu appelles POO. Faire des classes ce n'est pas faire de la POO. La POO serait plus une façon d'organiser son programme, quelque chose de plus abstrait que juste la création d'une classe?

C'est simplement que maintenant que tu sais faire des classes, il faut commencer à appliquer des grands principes qui sont rarement présentés sur ce site. Le premier, c'est que chaque classe doit avoir une responsabilité, et une seule. La pharmacie ne doit gérer que la pharmacie, pas son affichage, pas la saisie d'un client, juste : le boulot de la pharmacie. Si dans ta pharmacie tu sens qu'il y a un autre objet qui entre en jeu (par exemple, stock), à ce moment-là, il te faut une autre classe pour gérer le stock et rien que le stock, encapsulée dans ta pharmacie, à laquelle la pharmacie va déléguer une partie du boulot.

Bon, après, le problème de cet exo c'est qu'il est très limité en fonctionnalités donc qu'il est difficile de vouloir définir des vraies classes bien propres (à responsabilité unique) pour ça. C'est dû au fait que Python est à beaucoup plus haut niveau d'abstraction que Java (le langage pour lequel cet exo a été pensé).

Le truc à retenir c'est que faire des classes ne sert à rien si tu te retrouves à coder tout le programme dans une seule classe : autant faire un module et des fonctions.

-
Edité par nohar 21 mai 2014 à 10:55:20

Zeste de Savoir, le site qui en a dans le citron !
21 mai 2014 à 11:09:51

fred1599 a écrit:

On voit les différentes classes apparaître dans l'énoncé, non?

En fait non, j'avais pas compris que médicaments et clients étaient des classes également. Mais c'est parce que j'avais pas compris ce qu'était la POO.

En tout cas c'est un bon exercice pour comprendre ce concept. Maintenant que j'ai un peu mieux compris, je vais le refaire

Précepte: Le mieux est l'ennemi du bien
21 mai 2014 à 11:34:31

Technique toute simple : quand tu exprimes le fonctionnement de ton programme avec tes propres mots, souvent, les noms désignent des classes et les verbes leurs méthodes.

Après, ce n'est pas systématique, mais en général ça te donne un bon aperçu de l'architecture de ton programme.

-
Edité par nohar 21 mai 2014 à 11:35:48

Zeste de Savoir, le site qui en a dans le citron !
21 mai 2014 à 11:48:55

Merci pour l'astuce. Elle s'applique plutôt bien dans ce cas
Précepte: Le mieux est l'ennemi du bien
21 mai 2014 à 22:48:10

Suite à cette discussion sur la POO, voilà ce que j'ai changé:

La première erreur que j'ai faite dans mon premier programme c'était de considérer la pharmacie comme le corps du programme. J'ai corrigé cette erreur en dissociant le corps du programme de la construction des classes. J'ai également mis toutes les intéractions utilisateur (input) et les vérifications des valeurs dans le corps principal.

Aussi, j'ai essayé que chaque classe n'est qu'une responsabilité: agir que sur ses propres attributs. De plus les classes Medicament() et Client() sont autonome et peuvent resservir dans d'autres codes. J'ai créée des méthodes pour renvoyer les attributs des classes, pour éviter de toucher aux attributs directement. Est-ce une bonne idée?

Par contre la pharmacie de par sa liste de médicaments et de clients est dépendante des 2 premières classes. Est-ce une mauvaise chose?

J'ai créé une classe MenuPrincipal() qui n'a pas d'attributs, juste une méthode d'affichage. Est-ce une bonne idée, ou au contraire est-ce inutile?

Je n'ai pas mis la méthode quitter() car je ne la trouvais pas pertinente dans la classe Pharmacie(). Qu'en pensez-vous?

Une dernière question: Que pensez-vous du corps principal du programme? Est-il trop "sale", ou ça passe?

Voici ma nouvelle version de la pharmacie:

#python 3.4


##########################Les classes utilisées################################



class Pharmacie:
    """Caractérisée par une liste de clients et une liste de médicaments"""

    def __init__(self, clients, medicaments):
        self.clients = list(clients)
        self.medicaments = list(medicaments)

    def achat(self, client, medicament, quantite, montant):
        client.achat(montant)
        medicament.approvisionnement(-quantite)

    def approvisionnement(self, medicament, quantite):
        medicament.approvisionnement(quantite)

    def affichage(self):
        """Affiche les clients et les médicaments de la pharmacie"""
        print("")
        print("{:14}{}".format("Client", "Crédit"))
        print("-"*20)
        for client in self.clients:
            print("{:14}{:>5.2f}".format(
            client.renvoieNom(), client.renvoieCredit()))

        print("")
        print("{:14}{}".format("Médicament", "Quantité"))
        print("-"*22)
        for medicament in self.medicaments:
            print("{:14}{:>5}".format(
            medicament.renvoieNom(), medicament.renvoieStock()))
        print("")

    def lireClient(self, *clients):
        """Renvoie le premier client connu d'une liste"""
        for client in clients:
            for instance in self.clients:
                if client == instance.nom:
                    return instance

    def lireMedicament(self, *medicaments):
        """Renvoie le premier médicament connu d'une liste"""
        #paramètre optionnel pour avoir un tuple. Sans l'étoile (devient un
        #paramètre positionné) si un seul nom est entré, la boucle va
        #décomposer la chaîne lettre par lettre. Ce qu'on ne veut pas.
        for medicament in medicaments:
            for instance in self.medicaments:
                if medicament == instance.nom:
                    return instance


class Client:
    """Caractérisée par un nom et un crédit"""

    def __init__(self, nom, credit=0.0):
        self.nom = nom
        self.credit = credit

    def achat(self, montant):
        self.credit += montant

    def renvoieNom(self):
        return self.nom

    def renvoieCredit(self):
        return self.credit


class Medicament:
    """Caractérisée par un nom, un prix et un stock"""

    def __init__(self, nom, prix, stock=0):
        self.nom = nom
        self.prix = prix
        self.stock = stock

    def approvisionnement(self, quantite):
        self.stock += quantite

    def renvoieNom(self):
        return self.nom

    def renvoieStock(self):
        return self.stock

    def renvoiePrix(self):
        return self.prix


class MenuPrincipal:
    """Menu affichant les catégories à partir d'une liste"""

    def affichage(self, *categorie):
        for indice, element in enumerate(categorie):
            print("{}. {}".format(indice, element))



######################Initialisation des variables#############################



#Quelques clients
Fraktuur = Client("Fraktuur")
Khontuzion = Client("Khontuzion")
Antorce = Client("Antorce")

liste_clients = Fraktuur, Khontuzion, Antorce

#Quelques médicaments
Constipax = Medicament("Constipax", 3.85, 100)
Ogardavou = Medicament("Ogardavou", 12.99, 300)
Mo2kran = Medicament("Mo2kran", 2.40, 75)

liste_medicaments = Constipax, Ogardavou, Mo2kran

#La pharmacie
pharmacie = Pharmacie(liste_clients, liste_medicaments)

#Le menu principal
menu = MenuPrincipal()



#############################Corps principal###################################



#Début du programme
while True:

    print("")
    menu.affichage("Achat de médicament",
    "Approvisionnement en médicaments", "Etats des stocks et des crédits",
    "Quitter")
    print("")
    choix = input("Que voulez-vous faire: ")

    if choix.isdigit() and int(choix) in range(4):
        choix = int(choix)

        #ACHAT DE MÉDICAMENT
        if choix == 0:

            #On vérifie que le client existe
            #On renvoie l'instance client
            while True:
                client = pharmacie.lireClient(input("Client: "))
                if client:
                    break

            #On verifie que le médicament existe
            #On renvoie l'instance medicament
            while True:
                medicament = pharmacie.lireMedicament(input("Medicament: "))
                if medicament:
                    break

            #On vérifie que la quantité est pertinente
            while True:
                quantite = input("En quelle quantité: ")
                if quantite.isdigit() and (0 < int(quantite) <
                medicament.renvoieStock()):
                    break

            #Et on met à jour le stock du médicament
            medicament.approvisionnement(-int(quantite))

            #calcul du total a payé par le client
            total = int(quantite)*medicament.renvoiePrix()
            print("Le total a payé est de: {:.2f}€".format(total))

            #On vérifie que le montant payé par le client est pertinent
            while True:
                try:
                    montant = float(input("Montant payé par le client: "))
                    if montant >= 0:
                        break
                except:
                    continue

            #Et on met à jour le crédit du client
            client.achat(total - montant)
            print("")
            print("Le crédit de {} est de: {:.2f}€".format(client.renvoieNom(),
            client.renvoieCredit()))

        #APPROVISIONNEMENT EN MÉDICAMENTS
        if choix == 1:

            #On verifie que le médicament existe
            #On renvoi l'instance medicament
            while True:
                medicament = pharmacie.lireMedicament(input("Medicament: "))
                if medicament:
                    break

            #On vérifie que la quantité est pertinente
            while True:
                quantite = input("En quelle quantité: ")
                if quantite.isdigit() and int(quantite) > 0:
                    break
                else:
                    continue

            #Et on met à jour le stock du médicament
            medicament.approvisionnement(int(quantite))
            print("")
            print("Le stock de {} est maintenant de {} unités".format(
            medicament.renvoieNom(), medicament.renvoieStock()))

        #ÉTAT DES STOCKS ET DES CRÉDITS
        if choix == 2:
            pharmacie.affichage()

        #QUITTER
        if choix == 3:
            print("")
            print("Programme termniné")
            print("------------------")
            break

    else:
        continue

-
Edité par Olygrim 21 mai 2014 à 23:10:32

Précepte: Le mieux est l'ennemi du bien
Anonyme
23 mai 2014 à 19:57:41

Ça me semble pas mal tout ça :)

Les consignes sont à peu près respectées et c'est fonctionnel, bravo!

J'attends les suivants...

23 mai 2014 à 20:10:27

@olygrim

par soucis de propreté, j'enfermerais tes tuples lignes 113 & 120 dans des parenthèses.

Je chipote, mais c'est toujours bon de le savoir:D

@fred

bon, j’avais promis que j'y travaillerais, mais les révisions du  brevet (blanc), tout ça....:euh:

J'avais commencé un code mais il ne marche pas super et faudrait que je trouve le temps de remettre le nez dedans.

-
Edité par pythan 23 mai 2014 à 20:10:55

Bevet Breizh! Breizh dizalc'h! Betek an trec'h! Ha mallozh ruz d'ar c'hallaoued! Trouvez votre voie
Anonyme
23 mai 2014 à 20:16:25

Ligne 228, 229 je ne sais pas s'ils sont utiles ?

[EXERCICE POO] Pharmacie

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown