Avant propos
Design pattern MVC
Ce tutoriel présente le pattern MVC (Model-View-Controler) et une de ses applications possibles dans AutoIt.
Le pattern MVC répond à une problématique d'organisation du code et de maintenabilité. Le principe est de découper le logiciel en trois couches :
- Le modèle : couche permettant de stocker/récupérer les données.
- La vue : couche permettant d'afficher les données et d'intéragir avec l'utilisateur.
- Le contrôleur : couche permettant de traiter les données.
Le modèle n'intéragit pas directement avec la vue. Toutes les interactions entre les données stockées et les données affichées sont traitées par le contrôleur.
Cette présentation succinte suffira pour le reste du tutoriel. Pour des informations complémentaires sur le pattern MVC, vous pouvez lire
l'article wikipédia correspondant.
Programmation orientée objet
AutoIt n'étant pas un langage orienté objet, seul le principe de la programmation orientée objet nous intéressera ici. Si vous ne connaissez pas la POO, consultez
l'article wikipédia correspondant.
Architecture AutoIt
Exemple avec la gestion d'une bibliothèque
Nous allons utiliser comme exemple, une gestion de bibliothèque. Nous pourrons lister les livres présents dans notre bibliothèque et afficher les informations sur ces livres.
I - Création du projet
Une des applications possibles en AutoIt, pour le pattern MVC, est de séparer votre répertoire de projet en 3 sous-dossiers :
Code : Tout sélectionner
D:\Projects\AutoIt\Library>dir
[...]
25/06/2011 11:57 <DIR> .
25/06/2011 11:57 <DIR> ..
25/06/2011 11:57 <DIR> controler
25/06/2011 11:57 <DIR> model
25/06/2011 11:57 <DIR> view
0 File(s) 0 bytes
5 Dir(s) 277 588 176 896 bytes free
Ce découpage vous permettra d'ores et déjà de réfléchir à la position qu'occupent les fonctions que vous codez. Toutes les fonctions commençant par GUI devront, logiquement, se trouver dans le dossier "view". Tous les accès aux fichiers, aux bases de données, etc. se trouveront dans le dossier "model". Le reste se trouvera alors dans le dossier "controler"
Dans le cadre du projet, et ceci sera vrai pour la plupart de vos projets, vous aurez besoin de deux répertoires supplémentaires :
- Un répertoire "lib" à la racine du projet, pour y déposer vos UDF.
- Un répertoire "db" à la racine du projet, pour assurer la persistance de vos données.
II - Point d'entrée de l'application
Vous aurez besoin de créer un point d'entrée de votre application. C'est le script principal, que vous devrez exécuter et compiler pour que votre application fonctionne. Nous allons donc créer un fichier "main.au3" à la racine du projet.
► Afficher le textemain.au3
Code : Tout sélectionner
#cs ----------------------------------------------------------------------------
Auteur: Docteur
Fonction du Script :
Point d'entrée de l'application Library.
#ce ----------------------------------------------------------------------------
; Définition des variables globales
Opt("GUIOnEventMode", 1)
; Inclusion des bibliothèques
#include <Array.au3>
#include "lib/UDF_ArraysUtils.au3"
; Inclusion des modèles
#include "model/Book.au3"
; Inclusion des vues
#include "view/book/list.au3"
#include "view/book/show.au3"
; Inclusion des contrôleurs
#include "controler/book.au3"
; Action à effectuer par défaut
controler_book_list()
; Pause dans le script
While(True)
Sleep(10)
WEnd
On peut constater qu'il n'y a, dans ce fichier, que les imports des fichiers. Aucune logique métier ni aucun algorithme. Ce point d'entrée sert juste à rediriger vers l'action à effectuer par défaut. Ici, la méthode "controler_book_list()" est appelée au lancement du script.
III - Création des modèles
Les modèles doivent gérer indépendamment la persistance des données. Ils doivent offrir une interface complète permettant de gérer les cas d'utilisation.
Dans le cadre du projet, nous utiliserons un fichier CSV pour stocker nos données.
Le modèle "Livre" contient :
- un identifiant,
- un titre,
- un auteur,
- une description courte.
Nous allons donc créer un fichier "database.csv" dans le dossier "db/". Il contiendra 4 livres :
Code : Tout sélectionner
1;Stupeurs et tremblements;Amélie Nothomb;Amélie, fille de Belges qui vécut sa petite enfance au Japon, a toujours admiré le raffinement et l’art de vivre du pays.
2;Le Rouge et le Noir;Stendhal;Le roman compte deux parties : la première retrace le parcours de Julien Sorel dans la petite ville de Verrières et plus particulièrement son entrée chez les Rênal.
3;Les Misérables;Victor Hugo;L'action se déroule en France au début du XIXe siècle encadrée par les deux grands combats que sont la Bataille de Waterloo (1815) et les émeutes de juin 1832.
4;Candide;Voltaire;Candide est un jeune garçon vivant au château du baron de Thunder-ten-tronckh. Il a pour maître Pangloss, philosophe qui enseigne la « métaphysico-théologo-cosmolo-nigologie »
Ensuite, il nous faut construire l'objet associé au livre. L'objet "Book" ne doit s'occuper que de la récupération et l'enregistrement de livres. Il doit gérer une interface claire pour être ensuite utilisé dans les contrôleurs. Nous allons donc créer l'interface "IBook.au3" dans le dossier "model/".
Tout d'abord, voici la liste des fonctions dont nous aurons besoin :
- Récupérer un livre en fonction de son titre.
- Récupérer un livre en fonction de son identifiant.
- Lister tous les livres.
- Gérer les attributs d'un livre.
► Afficher le texteIBook.au3
Code : Tout sélectionner
#cs ----------------------------------------------------------------------------
Auteur: Docteur
Fonction du Script :
Interface du modèle "Livre".
#ce ----------------------------------------------------------------------------
; Fonctions de liste
#cs ----------------------------------------------------------------------------
Fonction du Script :
Récupère les identifiants de tous les livres disponibles.
#ce ----------------------------------------------------------------------------
Func model_book_getAllBookIds()
EndFunc
; Fonctions de gestion d'un livre
#cs ----------------------------------------------------------------------------
Fonction du Script :
Récupère les informations d'un livre en fonction de son identifiant.
#ce ----------------------------------------------------------------------------
Func model_book_getBookById($id)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Récupère les informations d'un livre en fonction de son titre.
#ce ----------------------------------------------------------------------------
Func model_book_getBookByTitle($title)
EndFunc
; Getters et setters des attributs d'un livre
Func model_book_getId()
EndFunc
Func model_book_setId($id)
EndFunc
Func model_book_getTitle()
EndFunc
Func model_book_setTitle($title)
EndFunc
Func model_book_getAuthor()
EndFunc
Func model_book_setAuthor($author)
EndFunc
Func model_book_getShortDescription()
EndFunc
Func model_book_setShortDescription($shortdescription)
EndFunc
Une fois cette interface définie, il faut l'implémenter. Copiez votre interface et créez le fichier "Book.au3". Ce fichier sera l'implémentation de votre interface. L'interface ne sera pas compilée, elle servira uniquement de documentation pour votre code.
► Afficher le texteBook.au3
Code : Tout sélectionner
#cs ----------------------------------------------------------------------------
Auteur: Docteur
Fonction du Script :
Implémentation du modèle "Livre".
#ce ----------------------------------------------------------------------------
; Dans cet exemple, nous stockerons les livres dans un fichier CSV.
Global $_model_book_CSV_file = @ScriptDir & "/db/database.csv"
Global $_model_book_delimiter = ";"
; Auto-increment id
Global $__model_book_ITERATION = 1
; Colonnes représentant le livre
Global Enum $__model_book_ID = 0, _
$__model_book_TITLE, _
$__model_book_AUTHOR, _
$__model_book_SHORTDESCRIPTION
; Attributs de mon livre courant
Global $_model_book_current[4]
; Fonctions de liste
#cs ----------------------------------------------------------------------------
Fonction du Script :
Récupère les identifiants de tous les livres disponibles.
#ce ----------------------------------------------------------------------------
Func model_book_getAllBookIds()
Local $file
Local $bookIdsArray[1]
$file = FileOpen($_model_book_CSV_file, 8)
While True
$line = FileReadLine($file)
If @error = -1 Then ExitLoop
Local $book = StringSplit($line, ";", 3)
If IsArray($book) Then
_ArrayInsertAndRedim($bookIdsArray, $book[$__model_book_ID])
EndIf
Wend
FileClose($file)
Return $bookIdsArray
EndFunc
; Fonctions de gestion d'un livre
#cs ----------------------------------------------------------------------------
Fonction du Script :
Récupère les informations d'un livre en fonction de son identifiant.
#ce ----------------------------------------------------------------------------
Func model_book_getBookById($id)
Local $index
$file = FileOpen($_model_book_CSV_file, 8)
While True
$line = FileReadLine($file)
If @error = -1 Then ExitLoop
Local $book = StringSplit($line, $_model_book_delimiter, 3)
If $book[$__model_book_ID] = $id Then
$_model_book_current[$__model_book_ID] = $id
$_model_book_current[$__model_book_TITLE] = $book[$__model_book_TITLE]
$_model_book_current[$__model_book_AUTHOR] = $book[$__model_book_AUTHOR]
$_model_book_current[$__model_book_SHORTDESCRIPTION] = $book[$__model_book_SHORTDESCRIPTION]
ExitLoop
EndIf
Wend
FileClose($file)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Récupère les informations d'un livre en fonction de son titre.
#ce ----------------------------------------------------------------------------
Func model_book_getBookByTitle($title)
Local $index
$file = FileOpen($_model_book_CSV_file, 8)
While True
$line = FileReadLine($file)
If @error = -1 Then ExitLoop
Local $book = StringSplit($line, $_model_book_delimiter, 3)
If $book[$__model_book_TITLE] = $title Then
$_model_book_current[$__model_book_ID] = $book[$__model_book_ID]
$_model_book_current[$__model_book_TITLE] = $book[$__model_book_TITLE]
$_model_book_current[$__model_book_AUTHOR] = $book[$__model_book_AUTHOR]
$_model_book_current[$__model_book_SHORTDESCRIPTION] = $book[$__model_book_SHORTDESCRIPTION]
ExitLoop
EndIf
Wend
FileClose($file)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Modifie ou crée le livre courant dans la base de données.
#ce ----------------------------------------------------------------------------
Func model_book_saveBook()
Local $file
Local $newFileContent = ""
; Lecture
$file = FileOpen($_model_book_CSV_file, 8)
While True
Local $line = FileReadLine($file)
If @error = -1 Then ExitLoop
Local $book = StringSplit($line, $_model_book_delimiter, 3)
If $book[$__model_book_ID] <> $_model_book_current[$__model_book_ID] Then
$newFileContent &= $line & @CRLF
EndIf
WEnd
$newFileContent &= _ArrayToString($_model_book_current, $_model_book_delimiter)
FileClose($file)
; Ecriture
$file = FileOpen($_model_book_CSV_file, 10)
FileWrite($file, $newFileContent)
FileClose($file)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Crée un nouveau livre.
#ce ----------------------------------------------------------------------------
Func model_book_newBook()
$_model_book_current[$__model_book_TITLE] = "Nouveau livre"
$_model_book_current[$__model_book_AUTHOR] = "Nouvel auteur"
$_model_book_current[$__model_book_SHORTDESCRIPTION] = "Nouvelle description"
$_model_book_current[$__model_book_ID] = $__model_book_ITERATION
$__model_book_ITERATION += 1
EndFunc
; Getters et setters des attributs d'un livre
Func model_book_getId()
Return $_model_book_current[$__model_book_ID]
EndFunc
Func model_book_setId($id)
$_model_book_current[$__model_book_ID] = $id
EndFunc
Func model_book_getTitle()
Return $_model_book_current[$__model_book_TITLE]
EndFunc
Func model_book_setTitle($title)
$_model_book_current[$__model_book_TITLE] = $title
EndFunc
Func model_book_getAuthor()
Return $_model_book_current[$__model_book_AUTHOR]
EndFunc
Func model_book_setAuthor($author)
$_model_book_current[$__model_book_AUTHOR] = $author
EndFunc
Func model_book_getShortDescription()
Return $_model_book_current[$__model_book_SHORTDESCRIPTION]
EndFunc
Func model_book_setShortDescription($shortdescription)
$_model_book_current[$__model_book_SHORTDESCRIPTION] = $shortdescription
EndFunc
Voici une implémentation de l'interface IBook. Les variables ne sont pas réutilisées à l'extérieur de ce fichier. Seules les méthodes présentes dans l'interface doivent être utilisées.
L'implémentation utilise la méthode _ArrayInsertAndRedim(), qui se trouve dans le fichier "lib/UDF_ArrayUtils.au3".
► Afficher le texteUDF_ArrayUtils.au3
Code : Tout sélectionner
#cs ----------------------------------------------------------------------------
Fonction du Script :
Redimensionne et insère une donnée dans un tableau
#ce ----------------------------------------------------------------------------
Func _ArrayInsertAndRedim(ByRef $array, $value)
$indexLastElement = UBound($array)
ReDim $array[$indexLastElement+1]
$array[$indexLastElement] = $value
EndFunc
Nous avons construit le modèle, nous pouvons maintenant créer les vues et le contrôleur.
IV - Création des vues
Nous avons deux vues : "list.au3" et "show.au3". Ces deux fichiers sont placés dans le dossier "view/book/".
Gestion de l'affichage de la liste :
► Afficher le textelist.au3
Code : Tout sélectionner
#cs ----------------------------------------------------------------------------
Auteur: Docteur
Fonction du Script :
Fenêtre de la liste des livres.
#ce ----------------------------------------------------------------------------
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <GUIListBox.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Global $_view_book_list_window
Global $_view_book_list_listcontrol
; Affichage d'une fenêtre unique pour l'application.
view_book_list_prepare()
#cs ----------------------------------------------------------------------------
Fonction du Script :
Préparation de la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_list_prepare()
$_view_book_list_window = GUICreate("Ma bibliothèque", 250, 250)
GUISetOnEvent($GUI_EVENT_CLOSE, "view_book_list_close", $_view_book_list_window)
GUICtrlCreateLabel("Liste des livres disponibles", 8, 8, 128, 17)
$_view_book_list_listcontrol = GUICtrlCreateList("", 8, 32, 217, 175)
GUICtrlCreateButton("Voir le livre", 128, 216, 97, 25, $WS_GROUP)
GUICtrlSetOnEvent(-1, "_view_book_list_showBook")
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Définition des données à afficher dans la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_list_setData($dataList)
GUICtrlSetData($_view_book_list_listcontrol, $dataList)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Affichage de la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_list_show()
GUISetState(@SW_SHOW, $_view_book_list_window)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Fermeture de la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_list_close()
; La fermeture de la fenêtre provoque l'arrêt du script.
Exit
EndFunc
; Fonctions privées
#cs ----------------------------------------------------------------------------
Fonction du Script :
Fonction appelée lors du clic sur le bouton "Voir le livre".
#ce ----------------------------------------------------------------------------
Func _view_book_list_showBook()
Local $bookTitle = GUICtrlRead($_view_book_list_listcontrol)
controler_book_show($bookTitle)
EndFunc
Gestion de l'affichage des informations d'un livre :
► Afficher le texteshow.au3
Code : Tout sélectionner
#cs ----------------------------------------------------------------------------
Auteur: Docteur
Fonction du Script :
Fenêtre des informations d'un livre.
#ce ----------------------------------------------------------------------------
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Global $_view_book_show_window
Global $_view_book_show_authorLabel
Global $_view_book_show_titleLabel
Global $_view_book_show_descriptionEdit
; Affichage d'une fenêtre unique pour l'application.
view_book_show_prepare()
#cs ----------------------------------------------------------------------------
Fonction du Script :
Préparation de la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_show_prepare()
$_view_book_show_window = GUICreate("Informations sur le livre", 300, 250)
GUISetOnEvent($GUI_EVENT_CLOSE, "view_book_show_close", $_view_book_show_window)
GUICtrlCreateLabel("Auteur :", 16, 8, 41, 17)
GUICtrlCreateLabel("Titre :", 16, 32, 31, 17)
GUICtrlCreateLabel("Description :", 16, 56, 63, 17)
$_view_book_show_authorLabel = GUICtrlCreateLabel("", 112, 8, 281, 17)
$_view_book_show_titleLabel = GUICtrlCreateLabel("", 112, 32, 281, 17)
$_view_book_show_descriptionEdit = GUICtrlCreateEdit("", 16, 80, 281, 129, $ES_MULTILINE)
GUICtrlSetState($_view_book_show_descriptionEdit, $GUI_DISABLE)
GUICtrlCreateButton("Fermer", 224, 224, 73, 25, $WS_GROUP)
GUICtrlSetOnEvent(-1, "view_book_show_close")
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Définition des données à afficher dans la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_show_setData($title, $author, $shortDescription)
GUICtrlSetData($_view_book_show_titleLabel, $title)
GUICtrlSetData($_view_book_show_authorLabel, $author)
GUICtrlSetData($_view_book_show_descriptionEdit, $shortDescription)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Affichage de la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_show_show()
GUISetState(@SW_SHOW, $_view_book_show_window)
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Fermeture de la fenêtre.
#ce ----------------------------------------------------------------------------
Func view_book_show_close()
GUISetState(@SW_HIDE, $_view_book_show_window)
EndFunc
Les vues ont 4 méthodes publiques :
- prepare(), qui permet de créer la fenêtre.
- setData(), qui permet de renseigner les données dynamiques de la fenêtre.
- show(), qui permet d'afficher la fenêtre.
- close(), qui permet de fermer la fenêtre.
Ces 4 méthodes devraient permettre au contrôleur de gérer l'ensemble de vos fenêtres.
V - Création du contrôleur
Nous arrivons au dernier élément de l'application : le contrôleur. Il fera le lien entre la vue et le modèle. Nous devons créer un contrôleur "book.au3" dans le dossier "controler/".
► Afficher le textebook.au3
Code : Tout sélectionner
#cs ----------------------------------------------------------------------------
Auteur: Docteur
Fonction du Script :
Contrôleur relié à la gestion des livres.
#ce ----------------------------------------------------------------------------
#cs ----------------------------------------------------------------------------
Fonction du Script :
Action pour lister les livres.
#ce ----------------------------------------------------------------------------
Func controler_book_list()
Local $dataList
Local $index
Local $lastIndex
Local $bookIds
; Récupération de la liste des identifiants des livres.
$bookIds = model_book_getAllBookIds(1)
$lastIndex = UBound($bookIds) - 1
For $index = 0 To $lastIndex
; Récupération du livre.
model_book_getBookById($bookIds[$index])
; Transformation de la liste des identifiants en chaîne de caractères
; pour le contrôle "List", sous la forme "1|2|3|4|5".
$bookTitle = model_book_getTitle()
$dataList &= $bookTitle
If $index <> $lastIndex Then
$dataList &= "|"
EndIf
Next
; Définition des données.
view_book_list_setData($dataList)
; Affichage de la fenêtre de la liste des livres.
view_book_list_show()
EndFunc
#cs ----------------------------------------------------------------------------
Fonction du Script :
Action pour afficher le livre sélectionné.
#ce ----------------------------------------------------------------------------
Func controler_book_show($bookTitle)
Local $index
Local $lastIndex
; Récupération du livre en fonction du titre passé en paramètre.
$book = model_book_getBookByTitle($bookTitle)
; Définition des données.
view_book_show_setData(model_book_getTitle(), model_book_getAuthor(), model_book_getShortDescription())
; Affichage de la fenêtre d'informations d'un livre.
view_book_show_show()
EndFunc
Le contrôleur possède deux méthodes, qui correspondent à nos deux vues. Ces deux méthodes permettent de gérer l'affichage de nos vues.
VI - Conclusion
Voilà, le projet est terminé. Vous trouverez ci-joint à ce post le schéma de l'architecture finale et le code source de l'application.
Merci de laisser un commentaire pour donner votre avis sur les méthodologies que vous utilisez pour la programmation, ainsi que pour améliorer le contenu de ce tutoriel.
Cordialement,
Le docteur.