L'usage du Singleton

skimpyskimpy Membre
08:53 modifié dans API AppKit #1
Bonjour,

Je suis en train de lire le livre sur les Design Pattern et je viens de découvrir le chapitre Singleton. Je me demandais si je devais utiliser le pattern Singleton dans le cas suivant :

J'ai un premier contrôler (AppController) qui contient un NSMutableArray (appelons-le monTableauDePersonne) dans lequel je stocke des objets de la classe Personne. J'ai créé un autre fichier NIB (pour les Préférences) avec son contrôleur associé PreferenceController (le File's owner est renseigné avec la classe PreferenceController). Dans ma fenêtre Préférence, j'aimerais utiliser une NSTableView pour afficher des informations contenues dans le tableau monTableauDePersonne.

Est-ce que je dois utiliser le pattern Singleton pour mon tableau ou est-ce que je dois procéder de la façon suivante  :
- Dans mon AppController, je possède un pointeur sur PreferenceController
- Dans PreferenceController, je déclare un pointeur sur NSMutableArray et une méthode pour setter ce pointeur
- Dans AppController, j'invoque la méthode de PreferenceController avec comme paramètre le pointeur sur mon NSMutableArray de AppController ?

J'espère que j'ai été assez explicite.

Merci pour votre aide.

Philippe

Réponses

  • AliGatorAliGator Membre, Modérateur
    08:53 modifié #2
    Hello

    Bonne question.

    Pour moi, un Singleton se justifie plutôt pour des "services" en général (façon "boite à  outils", genre si tu as une classe qui te sert d'interface/boite à  outils pour communiquer avec ton WebService, par exemple), ou pour des objets qui sont réellement uniques par nature parce qu'il n'y a vraiment qu'une instance (UIApplication car il n'y a bien qu'une seule application courante, NSNotificationCenter car il n'y a qu'un seul centre de notifications global, ...).

    Dans les autres cas, en général j'évite le pattern singleton, car pour moi dans les cas autres que ces derniers pour lesquels ça se justifie, cela peut masquer une mauvaise architecture du projet.

    Du coup pour ton cas le pattern Singleton ne me semble pas forcément correspondre à  tes besoins.
    Pour moi tu as un PreferencesController qui doit savoir afficher une liste de personnes (quelle qu'elle soit, on sait jamais dans ton appli un jour tu pourras avoir à  en gérer plusieurs). Liste que tu dois donc lui passer en paramètre.
    Et il faut voir l'aspect réutilisable aussi : faire qu'une classe (comme ton PreferencesController) utilise un Singleton (celui dans lequel tu pensais mettre ton tableau) fait qu'ils sont fortement dépendants l'un de l'autre et que si tu veux un jour utiliser ton PreferenceController dans un autre projet, tu seras obligé d'avoir aussi le Singleton qui va avec... si dans cet autre projet tu n'as pas une mais plusieurs listes de personnes cela ne va plus coller non plus... Alors que si tu lui passes en paramètres tu n'as plus cette contrainte.

    Quand on peut faire du loose-coupling, réduire les dépendances au maximum, c'est quand même mieux au final. Car si les choses sont trop liées le jour où tu veux changer un petit truc tu dois tout changer partout pour que l'ensemble continue de marcher, tu ne peux pas faire par petit bout si tout est dépendant du reste.

    Bon après ce n'est que mon avis, l'architecture d'une appli ce n'est jamais une seule bonne solution, juste des bonnes pratiques et de l'expérience.
  • mpergandmpergand Membre
    08:53 modifié #3
    Salut Philippe,

    Pour moi, c'est la gestion des préférences qui est un parfait exemple de singleton.
    De plus, faire apparaà®tre les données de l'appli dans le panneau de préférences est un peu curieux, puisque généralement les préférences agissent sur l'aspect global des données de l'appli, pas sur les données elle-mêmes.

    Ici je parle des préférences globales à  l'application.
    Mais on peut aussi avoir des préférences spécifiques pour chaque document.
    Par ex, si tu veux exclure certaines personnes de ton tableau, dans ce cas, je ferais ça directement dans l'interface de la fenêtre document (ou une fenêtre de dialogue à  part du panneau de prefs).

    [grillé par Aligator]
  • AliGatorAliGator Membre, Modérateur
    08:53 modifié #4
    Je plussoie mpergand : de manière générale les préférences globales d'une application peuvent tout à  fait être implémentées sous forme d'un singleton. Surtout côté "Modèle".
    D'ailleurs, la classe NSUserDefaults de Cocoa, qui permet de gérer les préférences, les sauver et les retrouver entre chaque lancement de l'appli, est un singleton elle-même.
    Par exemple si ton PreferenceController gère des données globales à  l'application (genre une préférence "ouvrir la fenêtre principale au démarrage" ou "afficher Nom, Prénom plutôt que Prénom, Nom" dans les listes de personnes) alors tu peux gérer ces réglages via un Singleton.

    Mais dans ton cas en fait comme mpergand je suis sceptique sur ton histoire de PreferenceController qui affiche des données de l'application comme ta liste de personnes... du coup ce ne sont pas trop des préférences globales, si ?

    Si on prend l'exemple du Carnet d'Adresses sur OSX par exemple, je vois mal dans les préférences afficher la liste des personnes de ton carnet d'adresses, liste qui peut changer d'un jour à  l'autre si tu la modifies.
    Donc soit ce sont des préférences globales, soit ce sont des réglages pour chaque personne. Si tu affiches la liste des personnes dans les Préférencespour modifier certains de leurs réglages, ton IHM ne va pas être très cohérente, surtout si plus tard l'utilisateur rajoute ou supprime des personnes dans les listes...
    Ou alors si c'est par exemple pour choisir dans les Préférences laquelle de ces personnes dans la liste est sensé représenter "toi" il reste plus logique de passer la liste des personnes (dans laquelle tu vas permettre à  l'utilisateur de sélectionner une des personnes comme étant "toi") plutôt que de fournir cette liste de personnes par Singleton. Par contre rien n'empêche à  tes préférences elles-même par contre d'être un Singleton, pour mémoriser l'ID unique de cette personne à  considérer comme "toi" dans tes préférences globales. Au final tes préférences seront un singleton (mais ça tu as déjà  NSUserDefaults pour ça), mais ta liste de personnes et ton modèle, lui, n'a pas de raison d'en être un.
  • skimpyskimpy Membre
    08:53 modifié #5
    Merci AliGator et mpergand pour vos explications.

    En fait, ce que j'ai cité dans mon premier post n'est qu'un exemple ... avant d'écrire une application complète, je préfère tester ce que je découvre sur des petits exemples (que je réutilise, là  j'ai repris un ancien programme qui contenait une fenêtre principale et une fenêtre de préférence). La question que je me posais était de savoir comment partager un tableau avec un autre controller et un autre fichier NIB. Dans les livres que je lis, les exemples présentés sont souvent "mono fenêtre" et "mono controller".

    Je pense avoir mieux cerné le principe du singleton. Encore merci pour votre aide.

    Philippe
  • AliGatorAliGator Membre, Modérateur
    08:53 modifié #6
    Eh bien si on prend par exemple une architecture "Master/Detail", où sur une fenêtre principale tu as une liste d'objet (disons des Livres, représentés par leurs titres dans une NSTableView), et que quand tu double-cliques sur un des livres tu as une autre fenêtre qui s'ouvre pour donner le détail sur le livre cliqué.
    Du coup tu as un exemple d'appli multi-fenêtre, et dans ce cas il faut passer ce qu'il faut d'un contrôlleur à  l'autre. Par exemple le contrôlleur de la 2e fenêtre doit être vu comme une boite noire qui prend en entrée un livre (objet modèle) et gère l'affichage des informations de ce livre (voire des modifications de ces infos si tu prévois de pouvoir les modifier) dans cette 2e fenêtre. Du coup il faut bien lui passer le livre (objet modèle) à  affiche en entrée avant de lui demander d'afficher la fenêtre, pour qu'il aille y piocher toutes les informations liées à  ce livre. Tu passes l'objet Livre du contrôleur 1 (qui a la liste de tous les livres, et sait quel livre est sélectionné / a été cliqué) au contrôleur 2 (qui lui n'a besoin que d'un livre, celui que tu lui passes et qu'il doit afficher). Nul besoin de Singleton dans cette histoire du coup (pas même pour gérer le modèle contenant tous les livres).
  • laudemalaudema Membre
    08:53 modifié #7
    Bonjour,

    Tu peux peut être utiliser les "bindings" si ton besoin est juste celui d'un tableau de AppDelegate dans un NSArrayController en vue d'affichage dans un .xib alors tu as dans l'onglet bindings des propriétés du contrôleur un pop-up qui te permet de choisir avec quoi lier. Tu prends Application et comme chemin tu mets delegate.monTableau. Il faut, bien sûr que ton AppDelegate soit le delegate de ton application mais ça, en général, c'est le cas ;).
    Remarque que, si besoin du tableau, tu peux avoir un IBOutlet de ton NSArrayController dans ton PreferencesController et par tonController.contentArray tu peux récupérer un "proxy" sur le tableau et en tirer des données avec les keyPath.
    C'est le chemin inverse à  l'habitude: ton xib va chercher le tableau au chargement et toi tu le récupères pour travailler dessus, plutôt que de prévoir le tableau dans ton PrefsController puis l'afficher ..

    PS: pour que tout marche bien ton tableau doit être une @property de AppDelegate et si tu veux ajouter/retirer des éléments (normalement non pour des préférences) tu dois écrire les assesseurs qui vont avec (insertObject:inTableauAtIndex: et removeObjectFromTableauAtIndex:) et autres méthodes du KVC.
    Inconvénients: nécessite de bien étudier la documentation des bindings et du Key Value Coding, avantage: tu peux avoir dans ton xib des références à  des objets qui ne sont pas au départ dans ta classe sans importer AppDelegate et tous ses objets.
    Il faut juste "Trouver la voie" disait Lao Tseu dans TinTin :)
Connectez-vous ou Inscrivez-vous pour répondre.