Valid XHTML     Valid CSS2    

Langages de scripts, automatisation de commandes et

production de documents structurés :

3. Langages de scripts et le patron de conception MVC

                     gilles.hunault "at" univ-angers.fr

 

Table des matières cliquable

  1. MVC, MVP, MVT ou BVC ?

  2. Des mini-MVC en Python

  3. Dans MVC, il y a M

  4. Dans MVC, il y a V

  5. Dans MVC, il y a C

 

Il est possible d'afficher toutes les solutions via ?solutions=1.

 

1. MVC, MVP, MVT ou BVC ?

Il arrive qu'on distingue les patrons de conception MVC, MVC-Model 2, MVP, MVT et BVC. De quoi s'agit-il exactement ? Est-ce applicable aux applications et projets de développement Web ?

Solution :  

 

2. Des mini-MVC en Python

Réindenter mini_mvc1_py.txt, mini_mvc2_py.txt et mini_mvc3_py.txt avant de vérifier que ces programmes s'exécutent en Python 2. Les convertir ensuite en Python 3. Que peut-on en déduire sur MVC ?


     # mini_mvc1_py.txt
     
     class Model:
     def get_post(self):
     return {"title":"A test","body":"An example.."}
     
     class View:
     def display(self,items):
     print 'Title:',items['title'],'\n'+'Body:',items['body']
     
     class Controller:
     def __init__(self):
     self.model = Model()
     self.view  = View()
     
     def main(self):
     post = self.model.get_post()
     self.view.display(post)
     
     mvc = Controller()
     mvc.main()
     

     # mini_mvc2_py.txt
     
     class Model(Control):
     users=dict(one='Bob',two='Michael',three='Dave')
     
     class View():
     def user(self,users):
     print(users.find('two'))
     
     class Control:
     def find(self,user):
     return self._look(user)
     
     def _look(self,user):
     if user in self.users:
     return self.users[user]
     else:
     return 'The data class ({}) has no {}'.format(self.userName(),user)
     
     def userName(self):
     return self.__class__.__name__.lower()
     
     def main():
     users=Model()
     find=View()
     print('--> The user two\'s "real name" is:\n')
     find.user(users)
     
     if __name__=="__main__":
     main()
     

     # mini_mvc3_py.txt
     
     # Source : http://tkinter.unpythonic.net/wiki/ToyMVC
     
     ## Some points to mention...
     ##
     ## The model knows nothing about the view or the controller.
     ## The view knows nothing about the controller or the model.
     ## The controller understands both the model and the view.
     ##
     ## The model uses observables, essentially when important data is changed,
     ## any interested listener gets notified through a callback mechanism.
     ##
     ## The following opens up two windows, one that reports how much money you
     ## have, and one that has two buttons, one to add money and one to remove
     ## money.
     ##
     ## The important thing is that the controller is set up to monitor changes
     ## in the model.  In this case the controller notices that you clicked a
     ## button and modifies the money in the model which then sends out a
     ## message that it has changed.  The controller notices this and updates
     ## the widgets.
     ##
     ## The cool thing is that anything modifying the model will notify the
     ## controller.  In this case it is the controller modifying the model, but it
     ## could be anything else, even another controller off in the distance
     ## looking at something else.
     ##
     ## The main idea is that you give a controller the model and view that it
     ## needs, but the model's can be shared between controllers so that when
     ## the model is updated, all associated views are updated. -Brian Kelley
     ##
     ## following is a Tkinter approximation of the original example.
     
     import Tkinter as tk
     
     class Model:
         def __init__(self):
             self.myMoney = Observable(0)
     
         def addMoney(self, value):
             self.myMoney.set(self.myMoney.get() + value)
     
         def removeMoney(self, value):
             self.myMoney.set(self.myMoney.get() - value)
     
     class View(tk.Toplevel):
         def __init__(self, master):
             tk.Toplevel.__init__(self, master)
             self.protocol('WM_DELETE_WINDOW', self.master.destroy)
             tk.Label(self, text='My Money').pack(side='left')
             self.moneyCtrl = tk.Entry(self, width=8)
             self.moneyCtrl.pack(side='left')
     
         def SetMoney(self, money):
             self.moneyCtrl.delete(0,'end')
             self.moneyCtrl.insert('end', str(money))
     
     class Controller:
         def __init__(self, root):
             self.model = Model()
             self.model.myMoney.addCallback(self.MoneyChanged)
             self.view1 = View(root)
             self.view2 = ChangerWidget(self.view1)
             self.view2.addButton.config(command=self.AddMoney)
             self.view2.removeButton.config(command=self.RemoveMoney)
             self.MoneyChanged(self.model.myMoney.get())
     
         def AddMoney(self):
             self.model.addMoney(10)
     
         def RemoveMoney(self):
             self.model.removeMoney(10)
     
         def MoneyChanged(self, money):
             self.view1.SetMoney(money)
     
     class Observable:
         def __init__(self, initialValue=None):
             self.data = initialValue
             self.callbacks = {}
     
         def addCallback(self, func):
             self.callbacks[func] = 1
     
         def delCallback(self, func):
             del self.callback[func]
     
         def _docallbacks(self):
             for func in self.callbacks:
                  func(self.data)
     
         def set(self, data):
             self.data = data
             self._docallbacks()
     
         def get(self):
             return self.data
     
         def unset(self):
             self.data = None
     
     class ChangerWidget(tk.Toplevel):
         def __init__(self, master):
             tk.Toplevel.__init__(self, master)
             self.addButton = tk.Button(self, text='Add', width=8)
             self.addButton.pack(side='left')
             self.removeButton = tk.Button(self, text='Remove', width=8)
             self.removeButton.pack(side='left')
     
     if __name__ == '__main__':
     root = tk.Tk()
     root.withdraw()
     app = Controller(root)
     root.mainloop()
     

Est-ce long de réécrire ces mini-MVC en php, en ruby ? Est-ce difficile de réécrire ces mini-MVC en php, en ruby ?

Solution :  

 

3. Dans MVC, il y a M

On voudrait disposer d'un mini framework php avec MySql que l'on nommera minifp dont voici le comportement :


     $gh>minifp --help
     
     minifp, syntaxe : minifp --help | --model optmodel | --data optmodel
     
      - le paramètre --help affiche cette aide
     
      - les options du paramètre --model sont tbl [ chmp:typ [chmp:typ]* | str ]
        où tbl désigne la table,
               chmp est un nom de champ,
               typ est le type du champ (chaine ou entier)
               str affiche la structure de la table
     
     $gh>minifp --model demo nom:chaine age:entier
     
     table demo crée avec deux champs
     
     $gh>minifp --model exemple nom:chaine prenom:chaine
     
     table exemple crée avec deux champs
     
     $gh>minifp --model demo prenom:chaine
     
     table demo mise à jour, trois champs désormais
     
     $gh>minifp --data demo nom:_CURIE age:30 prenom:_Marie
     
     Valeurs nom, age, prenom insérées dans la table demo
     

Est-ce raisonnable d'utiliser cette syntaxe pour définir un nombre important de champs dans une table ? Quelle autre solution pourriez-vous proposer ?

Remarque : le caractère souligné (qui permet d'ajouter une donnée textuelle au lieu de numérique) devra être enlevé lors de la finalisation du programme, le programme devant être capable de détecter le type des données après consultation du schéma de la table. Il manque aussi une création automatique des id...

Recommencer ensuite avec minifr (mini framework en Ruby) et minifpy (mini framework en Python).

Si le texte d'aide est long, quelle solution peut-on envisager ?

Solution :  

 

4. Dans MVC, il y a V

Compléter minifp, minifr et minifd pour obtenir le comportement suivant :


     $gh>minifp --help
     
     minifp, syntaxe : mini --help | --model optmodel | --data optmodel | --view optview
     
     - le paramètre --help affiche cette aide
     
     - les options du paramètre --model sont tbl [ chmp:typ [chmp:typ]* | str ]
        où tbl désigne la table,
               chmp est un nom de champ,
               typ est le type du champ (chaine ou entier)
               str affiche la structure de la table
     
     - les options du paramètre --view sont tbl [champ/valeur] [--mode optmode ]
       table affiche toute la table dont le nom est passé en paramètre
             ou seulement les enregistrements correspondant au filtre
             induit par un ET entre les arguments
       et où les options --mode sont show URI | go URI ;
       URI est une ressource écrite en REST ;
       show affiche l'URL associée alors que go l'affiche avec firefox.
     
     $gh>minifp --view tbl demo
     
     0001 CURIE 30 Marie
     
     $gh>minifp --view tbl demo --mode show
     
     http://.../tbl/demo
     
     $gh>minifp --view tbl demo --mode go
     
     # lancer firefox http://.../tbl/demo
     
     $gh>minifp --view tbl demo nom/Dupont
     ... # personnes de nom Dupont
     
     $gh>minifp --view tbl demo nom/Dupont/age/20
     ... # personnes de nom Dupont ayant 20 ans
     
     $gh>minifp --view tbl demo nom/Dupont/age/20+/ville/Angers
     ... # personnes de nom Dupont ayant 20 ans ou plus dont la ville est Angers
     
     

Remarque : pour afficher une table, on pourra utiliser catb_rex.txt ou affichage avec l'option -v -v -v de Mysql (le triplement de -v est volontaire).

Solution :  

 

5. Dans MVC, il y a C

Si on voulait compléter nos minif* pour en faire des vrais MVC, que faudrait-il ajouter ? Définir le comportement à l'aide d'exemples et implémenter cette partie C de MVC.

On pourra s'inspirer de TPLONG.

Solution :  

 

 

Code-source php de cette page ; code javascript utilisé. Retour à la page principale du cours.

 

 

retour gH    Retour à la page principale de   (gH)