Aller au contenu


Photo

AS et la POO

AppleScript POO

  • Please log in to reply
No replies to this topic

#1 FredoMkb

FredoMkb

    ...bosseigne...

  • Membres
  • PipPipPipPipPipPipPip
  • 2 645 Messages :
  • Configuration:iMac-SowLeopard
  • Sexe:Masculin
  • Localisation:StÉ
  • Passions:À part rien, absolument tout le reste !

Posté 11 novembre 2012 - 16:51

Bonjour à tous :)

Après l'immense et planétaire succès de notre échange consacré aux pointeurs de fonction avec AppleScript, voici une nouvelle discussion autour des possibilités de ce langage universellement utilisé par tous les développeurs de la terre et du cosmos !!! :yahoo:

:blink:

Oui... bon, ce n'est pas interdit de rêver non plus... non ? :D

Ok, soyons sérieux maintenant, nous allons donc essayer, cette fois, de voir les possibilités offertes par AS dans une approche de POO (Programmation Orientée Objet).

Avant toute chose, je tiens à le préciser tout de suite, je ne suis absolument pas un expert avec ces techniques, ne vous étonnez donc pas si je dis quelques bêtises ou si mes propos ne sont pas assez rigoureux ou précis, soyez alors indulgents et tâchons d'avancer ensemble, enfin, n'hésitez pas à me corriger si nécessaire (euh... non, je ne suis pas mazo, alors allez-y mollo quand-même, ok ? :huh: ).

Bon, malgré mon inconditionnel support de ce langage, je dois l'admettre, AppleScript n'est pas réputé dans ce domaine particulier du développement qui fait pourtant l'unanimité sur d'autres langages de programmation.

Mais, mettons quand-même les points sur les "i" et les barres sur les "T" : ce n'est pas parce que le procédural convient parfaitement à AS, et ce pratiquement pour la plupart des projets que nous avons à réaliser habituellement, que ce langage n'est pas pour autant capable de travailler en POO sans rien (ou presque) avoir à envier à d'autres langages.

Nous allons donc voir ici quelques petites bases de POO avec AS, rien de bien compliqué je vous rassure, mais qui peuvent éventuellement s'avérer utiles dans certains projets.

Avant d'entrer dans le vif du sujet, avec tout un tas de codes savoureux et enivrants (à consommer avec modération tout-de-même :siffle: ) , quelques petits mots en guise d'introduction mais, je vous rassure, ce n'est pas une initiation à la POO, il y a déjà de nombreux tutoriels assez clairs et complets sur la toile, c'est juste idée de rappeler quelques concepts de base et de les rapprocher à AppleScript.

C'est quoi la POO au juste ? :huh:

La "Programmation Orientée Objet", ou POO pour les intimes (qui sont des milliers, voire des millions aujourd'hui, je vous laisse donc imaginer le type d'intimité que cela suppose :huh: ), est un concept de programmation qui part du principe que tout, ou presque, peut être considéré, traité et manipulé comme étant un banal "objet" !

Si si, nous pouvons travailler avec du code informatique comme s'il s'agissait d'une simple chaise ou d'une anodine table... curieux non ?

En réalité, vous vous en doutez, les objets issues de la programmation informatique n'ont en fait rien en commun avec les vrais objets de notre réalité matérielle, il s'agit juste d'une abstraction virtuelle qui tente de s'inspirer de certaines particularités des objets du réel, mais la comparaison, ou plutôt le parallèle, ne vas pas au delà.

Donc, un code-objet informatique, ok... mais encore ? :blink:

Oui, je sais, ce n'est pas évident à concevoir... tentons donc d'imaginer tout simplement un bout de code capable de travailler de manière autonome et indépendante.

Par exemple, prenons n'importe quel bout de code conçu et développé en procédural, possédant ses propres variables et fonctions, enfermons le tout à l'intérieur d'un conteneur puis travaillons directement avec ce dernier, voilà en gros et très schématisé un "objet".

Pour résumer en deux mots, un "objet", en programmation, est tout code autonome, possédant ses propres propriétés et méthodes, encapsulé dans un conteneur.

Encapsuler, conteneur, propriétés, méthodes... et puis quoi encore ? <_<

En effet, ce sont des termes utilisés dans le jargon de la POO, elles peuvent faire peur au début mais vous allez voir que certaines sont tout simplement des synonymes des choses que nous connaissons et utilisons déjà, pour les autres, vous verrez, elles sont assez simples à comprendre.

Voyons donc quelques définitions :

Une "propriété" (ou attribut) est une information ou donnée sensée caractériser l'objet.

Ainsi, lorsque nous parlons par exemple d'un objet "voiture", sa couleur est une de ses caractéristiques et donc une propriété lui appartenant. Son poids, ses dimensions, sa motorisation et même sa marque sont des caractéristiques qui constituent autant de propriétés (ou attributs).

En AppleScript, les propriétés sont matérialisées par le mot clé "property", vous savez, ces fameuses variables que nous plaçons au début d'un code et qui, en plus d'être globales, possèdent la particularité de conserver leurs valeurs entre deux lancement d'un script.

Une "méthode" est une suite d'instructions exécutant une fonctionnalité propre à l'objet.

Suivant notre analogie avec un objet "voiture", on peut dire qu'une de ses méthodes est la fonctionnalité de démarrer, une autre étant celle d'accélérer ou de ralentir et aussi de s'arrêter. Bref, une méthode de l'objet n'est autre chose qu'une action réalisable par l'objet dont on peut contrôler l'exécution.

En AppleScript, une méthode n'est plus ni moins qu'une simple fonction, exactement identique à celles que nous savons déjà utiliser, sauf qu'elle est placée à l'intérieur d'un conteneur et qu'elle lui appartient.

Mais alors, comment fait-on pour créer un objet ? :wacko:

Et oui, avant de pouvoir manipuler quelque chose, il faut bien que cette chose existe... logique non ? :huh:

Dans la plupart des langages de programmation on crée un objet en deux étapes :

1. On défini d'abord une "classe", avec toutes ses propriétés et méthodes (c'est elle le fameux "conteneur" évoqué plus haut) ;

2. On crée ensuite un ou plusieurs "objets" de la classe par simple copie, on appelle ça une "instantiation" (voir : https://fr.wiktionar...wiki/instancier).

Dans AppleScript nous avons exactement le même processus, sauf que nous n'allons pas créer une "classe" à proprement parler, mais quelque chose de semblable, étant tout aussi fonctionnel, nommé en l'occurrence "Script-Objet".

Nous pourrons ensuite l'instancier en objet, c'est-à-dire, créer autant de copies que nous en aurons besoin, chacune étant du coup totalement indépendante des autres, et donc manipulables comme étant des objets uniques.

Pour résumer tout ça en quelques mots, en utilisant le jargon que nous venons d'apprendre (et oui, faudra bien commencer à s'y habituer), nous pouvons dire que pour faire de la POO avec AS nous devrons apprendre à :

- Créer des Scripts-Objets ;
- Encapsuler à l'intérieur des propriétés et des méthodes ;
- Instancier ces Scripts-Objets pour créer autant d'objets que nécessaire ;
- Utiliser les objets créés en manipulant leurs propriétés et en exécutant leurs méthodes.

Ok, tout ça est bien joli, mais, pourquoi faire de la POO ? :huh:

Alors là... vous me posez une véritable colle :(

Franchement, je ne sais pas... et même si les arguments pour sont légion, il n'y a qu'à faire une petite recherche sur le web pour s'en convaincre, personnellement j'ai encore beaucoup de mal à voir et même à profiter de tous les avantages qu'apporte cette méthode de développement.

Bon, vous l'aurez compris, ne comptez pas sur moi pour essayer de vous persuader des bienfaits de cette approche, surtout en ce qui concerne AppleScript, après, rien ne nous empêche de nous intéresser à la chose, chacun pourra ensuite juger si ça peut lui être utile ou pas, c'est en gros l'objet et même l'ambition inavouée de cette discussion.

Alors, concrètement, ça donne quoi au juste ? :w00t:

Et oui, vous avez raison, trêve de bavardage et passons tout de suite aux choses sérieuses... accrochez-vous, ça va secouer !

Ok, commençons donc par le début, à savoir, par la création d'une classe et l'instantiation d'un objet.

Nous l'avons vu, en AS on ne crée pas exactement une classe mais plutôt un "Script-Objet" (terme que nous allons abréger par l'acronyme "SO" dans la suite de cet échange), voilà un exemple :

script MonScriptObjet
-- Code
end script

Et oui, pourquoi faire compliqué quand ça peut être aussi simple... hein ? :D

En clair, on commence par le mot clé "script", puis on donne un nom à notre SO, on place ensuite l'ensemble du code que nous voulons y encapsuler puis, enfin, nous fermons le tout par un simple "end script", et c'est tout.

Pour l'instant notre joli SO, nommé "MonScriptObjet", ne fait rien du tout et ne sert donc absolument à rien... voyons donc comment intégrer des propriétés et des méthodes pour que, finalement, on puisse l'utiliser en tant qu'objet.

Pour que la suite des codes que nous allons réaliser puissent avoir un peu de sens, je vous propose de reprendre le scénario déjà abordé dans la discussion à propos des pointeurs de fonctions que nous avons vu récemment, à savoir, la gestion d'une petite association sportive qui propose des activités différentes à ses adhérents suivant leurs tranche d'âge.

Nous allons donc tenter de gérer les adhésions et les différentes activités proposées.

Pour commencer, essayons de définir quelles sont les propriétés qui vont caractériser nos adhésions, j'en vois personnellement quatre, à savoir :

1. Titre de l'adhésion : c'est une désignation textuelle qui nous permettra de l'afficher à chaque fois qu'on en aura besoin ;
2. Tranche d'âge : comme chaque adhésion s'applique à une tranche d'âge particulière, c'est ici que nous allons le définir ;
3. Tarif : le tarif de l'adhésion change suivant la tranche d'âge, c'est ici que nous allons définir ce montant ;
4. Activité : nous avons vu que chaque adhésion bénéficiait d'une activité suivant la tranche d'âge, c'est donc ici que nous allons la renseigner.

Voyons maintenant ce que ça donne en code AS pour l'adhésion des jeunes par exemple, en mettant les valeurs par défaut correspondantes (on reprend celles déjà utilisées précédemment) :


script AdhesionJeunes
property Titre : "Jeunes"
property Age : 25
property Tarif : 20
property Activite : "Compétition"
end script

Nous pouvons accéder aux propriétés du SO "AdhesionJeunes" et récupérer ou modifier leur valeurs, deux syntaxes peuvent être utilisées, soit par chemin soit par ciblage, voyons ça d'abord pour afficher une valeur, le titre par exemple :

Par chemin :

display dialog Titre of AdhesionJeunes

Par ciblage :

tell AdhesionJeunes to display dialog Titre of it

Et bien, pour les instructions simples, la syntaxe par chemin sera souvent la plus concise et directe, alors que la syntaxe par ciblage nécessite une notation "of it", qui peut paraître un peu redondante mais qui s'avère incontournable car elle évite toute forme d'ambigüité (nous verrons sûrement mieux sont utilité lorsque nous aborderons le concept d'héritage).

De la même manière, si nous souhaitons modifier la valeur de cette propriété "Titre", les deux syntaxes peuvent être employées :

Par chemin :

set Titre of AdhesionJeunes to "Formule pour les jeunes"

Par ciblage :

tell AdhesionJeunes to set Titre of it to "Formule pour les jeunes"

Ok, ajoutons maintenant quelques méthodes à notre SO afin de voir comment cela peut fonctionner.

Pour commencer, imaginons une méthode qui se charge de remettre toutes les valeurs par défaut à toutes les propriétés, ceci afin de pouvoir revenir en arrière en cas de fausse manipulation ou de maladresse, nous allons nommer cette méthode "initProp", conjonction des abréviations de "initialisation" et de "Propriété", voyons ça :

script AdhesionJeunes
property Titre : "Jeunes"
property Age : 25
property Tarif : 20
property Activite : "Compétition"

on initProp()
set {Titre, Age, Tarif, Activite} to {"Jeunes", 25, 20, "Compétition"}
end initProp
end script

Nous pouvons également ajouter deux autres méthodes, une qui nous permettra de récupérer l'ensemble des propriétés sous forme de liste, puis une autre qui aura pour rôle de changer la valeur de toutes les propriétés d'après une liste, comme ceci :

script AdhesionJeunes
property Titre : "Jeunes"
property Age : 25
property Tarif : 20
property Activite : "Compétition"

on initProp()
set {Titre, Age, Tarif, Activite} to {"Jeunes", 25, 20, "Compétition"}
end initProp

on getProp()
return {Titre, Age, Tarif, Activite}
end getProp

on setProp(Liste)
set {Titre, Age, Tarif, Activite} to Liste
end setProp
end script

Nous voyons ici une convention, ou plutôt habitude, assez courante en développement, celle d'utiliser les mots "get" et "set" suivant la nature de l'action qu'on demande :
- soit elle est consultative (lecture), c'est-à-dire qu'on cherche uniquement à récupérer certaines données, c'est alors "get" qu'on utilise ;
- soit elle est transformative (écriture), c'est à dire qu'on cherche à modifier certaines valeurs, c'est alors "set" qu'on utilise.

Petit détail, mais qui a son importance, la méthode "setProp" réclame comme argument une liste, celle-ci doit contenir quatre valeurs, toujours dans le même ordre et toujours du même type pour chacune d'elles, à savoir : le titre (type texte), la tranche d'âge (type nombre), le tarif (type nombre) et enfin l'activité (type texte).

Note : Dans la pratique ceci pourrait constituer une erreur de développement, en effet, le programme devrait normalement disposer d'un système de contrôle permettant de vérifier si les données fournies sont conformes à celles attendues et supportées. Nous ne verrons pas tout ça ici, ce n'est pas l'objet de la discussion, mais c'est un point important à ne pas ignorer dans vos développements.

Nous pouvons dès à présent créer un ou plusieurs objets à partir de cet SO, c'est ce qu'on appelle "instancier un objet", cela donne en AppleScript :

set monAdhesion to my AdhesionJeunes

C'est exactement comme pour tout autre type de variable, on lui affecte une valeur avec la commande "set ... to", sauf qu'ici la valeur est justement un Script-Objet.
Notez, comme pour les fonctions, l'utilisation du mot clé "my" afin d'éviter toute ambigüité.

Du coup cette variable nommée "monAdhesion" devient, grâce à l'instatiation, un objet du SO "AdhesionJeunes".

Comme nous l'avons vu précédemment, nous pouvons désormais interagir avec cet objet en exécutant ses propres méthodes. Si nous désirons par exemple modifier certaines propriétés, nous pouvons faire :

Par chemin :

setProp({"Pour les jeunes", 24, 25, "Compétitions régionales"}) of monAdhesion

Ou par ciblage :

tell monAdhesion to setProp({"Pour les jeunes", 24, 25, "Compétitions régionales"})

Vérifions si notre changement s'est bien réalisé :

Par chemin :

return getProp() of monAdhesion

Par ciblage :

tell monAdhesion to return getProp()

Si nous voulons annuler ces modifications pour revenir aux valeurs par défaut, nous n'avons plus qu'à exécuter la méthode d'initialisation :

Par chemin :

initProp() of monAdhesion

Par ciblage :

tell monAdhesion to initProp()

Ok, nous avons donc un joli petit Script-Objet pré-formaté pour l'adhésion des jeunes, nous pouvons même déjà l'instancier pour créer autant d'objets qu'on le voudrait, mais, justement, dans ce cas de figure tous les objets crées seront absolument identiques, or l'idée est de pouvoir les différencier pour qu'ils soient uniques et donc utilisables pour chaque réelle adhésion à l'association.

Il nous manque donc d'inclure certaines données, celles justement qui vont nous permettre d'identifier clairement chaque objet par rapport aux autres. La plupart de ces nouvelles données vont être évidemment nominatives car se rapportant à un adhérant, puis une valeur indépendante "Id" pour identifier clairement l'objet. Tout ceci pourrait se faire ainsi :

script AdhesionJeunes
-- Propriétés Adhésion
property Titre : "Jeunes"
property Age : 25
property Tarif : 20
property Activite : "Compétition"

-- Propriétés Adhérent
property Id : 0
property Adherent : {}

on initProp()
set {Titre, Age, Tarif, Activite} to {"Jeunes", 25, 20, "Compétition"}
end initProp

on getProp()
return {Titre, Age, Tarif, Activite}
end getProp

on setProp(Liste)
set {Titre, Age, Tarif, Activite} to Liste
end setProp

on getAdherent()
return Adherent
end getAdherent

on setAdherent(Liste)
set Adherent to Liste
end setAdherent
end script

Comme on le voit, deux nouvelles propriétés "Id" et "Adherent" vont nous permettre d'identifier clairement chaque objet instantcié et en plus nous pourrons ajouter toutes les informations concernant l'adhérent correspondant à chaque objet. Ces dernières infos pourraient être par exemple : le numéro d'adhérent, le nom, le prénom, l'âge, la date d'adhésion, etc.

Nous avons également prévu des méthodes standards pour pouvoir accéder aux données de l'adhérent et ainsi les gérer à partir de l'objet. Quant à l'identifiant "Id", comme il ne sera renseigné qu'à la création de chaque objet et qu'il ne sera plus touché par la suite, il n'est pas nécessaire de créer des méthodes dédiées, même si cela reste possible bien-sûr.

Voilà, c'est déjà assez long comme première petite approche à la POO avec AS, il reste évidemment plein de choses à dire et de tas d'autres tests et exemples à explorer, mais pour l'heure, je vous propose tout simplement, à partir du dernier code de SO d'exemple, de proposer vos propres solutions pour enregistrer les données de chaque adhérent, pensez seulement qu'on doit ensuite pouvoir les manipuler aisément afin des les actualiser à chaque fois qu'on en aura besoin.

N'hésitez pas à ajouter des infos qui pourraient vous paraître utiles ou nécessaires, toujours pour coller au mieux à notre scénario d'association sportive.
Faites également quelques essais d'instantiation afin de commencer à vous familiariser avec l'utilisation des objets.

Évidemment, comme d'hab, toutes les questions, remarques et suggestions sont les bienvenues... :)

Ce message a été modifié par Fredo d:o) - 11 novembre 2012 - 16:52 .

Fredo
"Un pas à la fois me suffit..." Gandhi
"Il n'y a rien de plus inutile que quelque chose d'inexistant. Il n'y a rien de plus utile que de tenter de le créer." FredoMkb





Also tagged with one or more of these keywords: AppleScript, POO

0 utilisateur(s) en train de lire ce sujet

0 membre(s), 0 invité(s), 0 utilisateur(s) anonyme(s)