Les modèles de conception sont souvent considérés comme un sujet plus avancé et sont donc ignorés ou négligés par les débutants en développement iOS ou OS X. Cependant, il existe un certain nombre de modèles de conception auxquels tout développeur aspirant iOS ou OS X sera confronté dès le premier jour. Le motif singleton est l'un de ces motifs.
Avant de commencer à examiner les techniques permettant de mettre en œuvre le motif singleton dans Swift et Objective-C, j'aimerais prendre quelques instants pour comprendre le motif singleton, ses avantages et ses inconvénients..
Le modèle singleton est inextricablement lié à la programmation orientée objet. La définition du motif singleton est simple, une seule instance de la classe singleton peut être créée ou est vivante à la fois..
Brent Simmons, cependant, nuance cette définition en faisant une distinction entre vrai singletons et fonctionnel singletons. Brent définit les vrais singletons comme des classes qui retournent toujours la même instance d'elle-même. Il n'est pas possible de créer plus d'une instance de la classe. Les singletons fonctionnels sont créés une fois et utilisés à plusieurs endroits..
Je suis sûr que beaucoup de développeurs ne classeraient pas les singletons fonctionnels en singletons, mais j'aime la distinction faite par Brent. Les singletons fonctionnels n'ont souvent pas les inconvénients typiques des singletons véritables. Nous examinerons ces inconvénients plus tard dans cet article..
Si vous connaissez le développement iOS ou OS X, vous remarquerez que les frameworks Apple utilisent le modèle singleton. Une application iOS, par exemple, ne peut avoir qu'une seule instance du UIApplication
classe, à laquelle vous pouvez accéder via le application partagée
méthode de classe.
UIApplication * sharedApplication = [UIApplication sharedApplication];
let sharedApplication = UIApplication.sharedApplication ()
Même si le UIApplication
classe vous donne accès à la UIApplication
singleton, rien ne vous empêche d'instancier explicitement un UIApplication
exemple.
UIApplication * newApplication = [[UIApplication alloc] init];
laisser newApplication = UIApplication ()
Le résultat, cependant, est une exception d'exécution. L’exception indique clairement qu’une seule instance de la UIApplication
la classe peut être en vie à tout moment. En d'autres termes, le UIApplication
la classe a été conçue avec le motif singleton à l’esprit.
*** Terminaison de l'application en raison d'une exception non interceptée 'NSInternalInconsistencyException', raison: 'Il ne peut y avoir qu'une seule instance UIApplication.'
L’avantage le plus évident du motif singleton est l’accessibilité. Prendre en compte UIApplication
classe à titre d'exemple. En important le framework UIKit, le UIApplication
singleton est accessible de n’importe où dans votre projet. Jetez un coup d’œil à l’exemple suivant de UIViewController
sous-classe.
#importation@interface ViewController: UIViewController @end
#import "ViewController.h" @implementation ViewController #pragma mark - #pragma mark Cycle de vie de la vue - (void) viewDidLoad [super viewDidLoad]; // Accéder à l'application Singleton UIApplication * application = [UIApplication sharedApplication]; @fin
Il est parfois utile ou essentiel qu’une seule instance d’une classe soit vivante à la fois. le UIApplication
La classe est un exemple de cette exigence. D'autres exemples peuvent inclure des classes pour la journalisation, la mise en cache ou les opérations d'E / S..
Cela dit, il est important de comprendre que les singletons sont un moyen d’accomplir le contrôle et le comportement. Les techniques de codage défensif peuvent vous donner le même résultat sans la surcharge mentale du motif singleton.
En créant un singleton, vous créez essentiellement un état global. Il est important que vous soyez au courant de cela. Il y a quelques années, Miško Hevery a écrit un excellent article sur le motif de singleton dans lequel il explique pourquoi ce motif devrait être évité. Miško souligne que l'état global est la principale raison pour laquelle les singletons sont nuisibles.
Il y a des exceptions cependant. Par exemple, les singletons qui sont immuables peuvent faire peu de mal. Vous créez toujours un état global, mais cet état est immuable. Miško mentionne également les enregistreurs en tant qu'application quelque peu acceptable du motif singleton, car l'état circule dans un sens, de votre application vers l'enregistreur..
La plupart des langages de programmation orientés objet considèrent le couplage étroit de modules comme une mauvaise pratique. En d'autres termes, il est recommandé de découpler les modules autant que possible. Cela met le motif de singleton dans un mauvais endroit et les singletons sont donc considérés comme une mauvaise pratique par de nombreux programmeurs respectés. Certains développeurs vont jusqu'à considérer cela comme un anti-motif qu'il faut éviter.
Pour mieux comprendre le problème, envisagez le scénario suivant. Vous avez créé une application iOS avec un composant réseau dans lequel vous accédez au UIApplication
singleton. Votre application iOS connaît un tel succès que vous envisagez de créer une application OS X. le UIApplication
Cependant, la classe n'est pas disponible sur OS X en raison de l'absence du framework UIKit. Cela signifie que vous devrez refactoriser ou modifier le composant réseau de l'application iOS..
Il existe un certain nombre de solutions pour résoudre ce problème, mais ce que je veux dire, c’est que vous avez étroitement couplé le module réseau au cadre UIKit, le UIApplication
classe en particulier.
Le couplage étroit est souvent étroitement associé à la réutilisabilité. Un graphe d'objet étroitement couplé est très souvent difficile à réutiliser sans refactorisation. Une mauvaise réutilisation est parfois inévitable, mais il faut certainement en tenir compte lors du développement de logiciels..
Créer un singleton en Objective-C est très facile à faire. Dans l'extrait de code suivant, nous créons et implémentons une classe de journalisation., Enregistreur
. Nous accédons à l'objet singleton à travers le sharedLogger
méthode de classe.
#importation@interface Logger: NSObject #pragma mark - #pragma mark Méthodes de classe + (Logger *) sharedLogger; @fin
La mise en œuvre est simple. Nous déclarons une variable statique _SharedInstance
qui tiendra une référence à l'objet singleton. Nous invoquons dispatch_once
, une Grand Central Dispatch fonction, et passons dans un bloc dans lequel nous initialisons une instance du Enregistreur
classe. Nous stockons une référence à l'instance dans _SharedInstance
.
#import "Logger.h" @implementation Logger #pragma mark - #pragma mark Méthodes de classe + (Logger *) sharedLogger static Logger * _sharedInstance = nil; static dispatch_once_t oncePredicate; dispatch_once (& oncePredicate, ^ _sharedInstance = [[self alloc] init];); return _sharedInstance; @fin
le dispatch_once
function assure que le bloc que nous passons est exécuté une fois pour la durée de vie de l'application. C’est très important car nous ne voulons initialiser qu’une instance du Enregistreur
classe.
le une foisPredicate
variable qui est passée comme premier argument de la dispatch_once
la fonction est utilisée par le dispatch_once
fonction pour s'assurer que le bloc n'est exécuté qu'une seule fois.
le sharedLogger
La méthode class retourne le Enregistreur
par exemple en renvoyant la référence stockée dans _SharedInstance
. L'implémentation de sharedLogger
peut paraître intimidant au début, mais je suis sûr que vous êtes d’accord pour dire que l’idée est très simple.
Pour implémenter le motif singleton dans Swift, nous utilisons des constantes de classe, qui ont été introduites dans Swift 1.2. Si vous rencontrez des problèmes avec l'extrait de code ci-dessous, assurez-vous que vous utilisez Xcode 6.3.+.
class Logger static let sharedInstance = Logger ()
Laissez-moi vous guider à travers la courte mise en œuvre du Enregistreur
classe. Nous commençons par déclarer une classe nommée Enregistreur
. Pour implémenter le motif singleton, nous déclarons une propriété de type, instance partagée
, de type Enregistreur
.
En utilisant le statique
mot-clé, le instance partagée
constante est liée à la Enregistreur
classe au lieu d'instances de la classe. le instance partagée
constante est appelée propriété type puisqu'il est lié au type, c'est-à-dire le Enregistreur
classe. Nous accédons à l'objet singleton à travers le Enregistreur
classe.
Logger.sharedInstance
Vous vous demandez peut-être pourquoi nous n'utilisons pas le dispatch_once
fonctionne comme nous l'avons fait dans l'implémentation d'Objective-C. Sous le capot, Swift utilise déjà dispatch_once
lors de l’initialisation de constantes statiques. C'est quelque chose que vous obtenez gratuitement à Swift.
Une autre approche courante pour implémenter le modèle singleton consiste à exploiter les types imbriqués. Dans l'exemple suivant, nous déclarons une propriété de type calculée., instance partagée
, de type Enregistreur
. Dans la fermeture de la propriété de type calculé, nous déclarons une structure nommée Singleton
. La structure définit une propriété de type constant, exemple
, de type Enregistreur
.
class Logger class var instance partagée: Logger struct Singleton instance de sortie statique: Logger = Logger () return Singleton.instance
L'accès à l'objet singleton est identique pour les deux stratégies. Si vous utilisez Swift 1.2, je vous recommande d'utiliser la première approche pour sa brièveté et sa simplicité..
Je suppose qu'il est tentant, si le seul outil dont vous disposez est un marteau, de tout traiter comme s'il s'agissait d'un clou. - Abraham Maslow
Lorsque j'ai entendu parler du motif singleton pour la première fois, j'étais enthousiasmé par son utilité dans mon prochain projet. Il est très tentant d'utiliser un outil qui semble résoudre de nombreux problèmes. À première vue, le motif singleton peut ressembler à une balle en argent ou à un marteau en or, mais ce n’est pas ce qu’il est..
Par exemple, si vous utilisez un singleton uniquement pour le rendre facilement accessible, vous utilisez peut-être le motif singleton pour les mauvaises raisons. Ce n'est pas parce qu'Apple utilise le modèle singleton dans ses propres frameworks que c'est la bonne solution à chaque problème.
Les singletons peuvent être très utiles, mais ils sont considérés par beaucoup de programmeurs expérimentés comme un anti-modèle. La plupart d'entre eux ont eu de mauvaises expériences avec le modèle pour arriver à cette conclusion. Apprendre de leurs erreurs et les utiliser avec parcimonie.
Je ne considère pas le motif singleton comme un anti-motif, mais c'est un motif qui doit être utilisé avec prudence. Si vous êtes tenté de transformer un objet en singleton, posez-vous la question de savoir s'il existe un autre moyen de résoudre le problème. Dans la plupart des cas, le modèle singleton n'est pas la seule solution disponible. Une solution alternative peut nécessiter plus de travail ou un peu de frais généraux, mais elle est probablement meilleure à long terme..
Les singletons fonctionnels auxquels Brent Simmons fait référence constituent souvent une alternative parfaitement valable aux vrais singletons. Il n'y a rien de mal à créer une instance d'une classe et à la transmettre aux objets qui en ont besoin. Considérez cette approche la prochaine fois que vous envisagez de créer un autre singleton.
Le motif singleton est simple et puissant, mais vous devez l’utiliser avec parcimonie. Certains de vos collègues peuvent vous déconseiller cette option, mais j'estime qu'il est important d'envisager son utilisation et de décider par vous-même si vous pensez que c'est un ajout utile à votre boîte à outils.