Les modèles de conception sont des modèles de solutions spécifiques (routines) qui peuvent être réutilisés pour des problèmes spécifiques dans des situations spécifiques qui surviennent constamment. Cet article résume les points clés de l'utilisation de 24 modèles de conception courants selon les trois catégories de création, de structure et de comportement, y compris les scénarios et solutions applicables et leurs implémentations Java correspondantes.
Le modèle de conception concerne un certain « problème » dans un certain « contexte » qui apparaît constamment. :
Le « problème » doit être récurrent et la « solution » doit être applicable à plusieurs reprises
« Problème » contient « un objectif » ; et "un ensemble de contraintes". Lorsque la solution établit un équilibre entre les deux, c'est un modèle utile
Les modèles de conception ne sont pas des lois. Les critères ne sont que des lignes directrices ; ajustez-les selon vos besoins lors de l'utilisation réelle. Il vous suffit de prendre des notes pour que les autres puissent comprendre clairement
De nombreux modèles apparemment nouveaux sont en fait des modèles existants
Principe de sélection des modèles : essayez de concevoir de la manière la plus simple, à moins que vous n'utilisiez des modèles de conception pour vous adapter aux changements possibles dans le futur, car les modèles de conception introduiront plus de classes. Pour des relations plus complexes, n'utilisez pas de modèles dans le but d'utiliser des modèles.
Les initiales anglaises des six principes réunis sont SOLID (stable), c'est pourquoi on l'appelle aussi le principe SOLID.
Il ne devrait jamais y avoir plus d'une raison pour qu'une classe change
Une classe n'a qu'une seule responsabilité, plutôt que deux. plusieurs responsabilités couplées dans une seule classe (par exemple, l'interface et la logique doivent être séparées).
Les entités logicielles telles que les classes, les modules et les fonctions doivent être ouvertes pour l'extension mais fermées pour les modifications
Ouvertes pour l'extension, fermées pour les modifications. interfaces et classes abstraites.
Les fonctions qui utilisent des pointeurs ou des références à des classes de base doivent pouvoir utiliser des objets de classes dérivées sans le savoir
Assurez-vous où la classe parent peut apparaître. , la sous-classe peut certainement apparaître. C'est la pierre angulaire de l'héritage et de la réutilisation.
Parlez uniquement à vos amis immédiats
Faible dépendance, chaque entité est la plus indépendante possible et les interactions sont minimisées.
La dépendance d'une classe à une autre doit dépendre de la plus petite interface possible
Le client ne doit pas dépendre de Il n'utilise pas la méthode. . Essayez d'utiliser plusieurs interfaces pour diviser et combiner des fonctions au lieu de coupler plusieurs fonctions avec une seule interface.
Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau
Les deux doivent dépendre des abstractions. Les abstractions ne doivent pas dépendre des détails. .
Dépend de l'abstraction (interface ou classe abstraite), pas du concret (classe concrète).
Le modèle de conception est un ensemble d'expériences de conception de code classifiées et cataloguées qui sont utilisées à plusieurs reprises, connues de la plupart des gens. Le but de l'utilisation de modèles de conception est de réutiliser le code, de le rendre plus facile à comprendre par les autres et de garantir sa fiabilité.
Les modèles de conception compliquent des problèmes apparemment simples. Cependant, la conception « simple » a une faible flexibilité, n'est pas pratique à développer dans le projet en cours et ne peut pas être utilisée dans d'autres projets, ce qui équivaut à un « code unique ». Le code du modèle de conception a une structure claire et est facile à développer dans le projet en cours. Il est également applicable à d'autres projets et constitue une conception universelle.
Après avoir été exposés aux modèles de conception, de nombreux programmeurs ont le sentiment d'être trop tard. Ils ont le sentiment de renaître et d'avoir atteint un nouveau niveau. Les modèles de conception peuvent être utilisés comme norme pour diviser les niveaux des programmeurs.
Cependant, nous ne pouvons pas tomber dans le piège des modèles et appliquer des modèles pour utiliser des modèles, sinon nous tomberons dans le formalisme.
Chaque modèle de conception implique plusieurs principes OO Lorsqu'il n'y a pas de modèle de conception approprié parmi lequel choisir, vous pouvez revenir aux principes OO Pour choisir ;
La meilleure façon d'utiliser des modèles est d'avoir différents modèles dans votre esprit et de voir où ces modèles peuvent être utilisés dans des conceptions ou des codes existants pour réutiliser l'expérience ;
Le pouvoir du partage du vocabulaire des modèles de conception (y compris les noms verbaux, la dénomination des classes et des méthodes dans le code) :
(1) Lorsque vous communiquez avec d'autres, mentionnez le nom du modèle de conception, et il sera masqué . Contient ses modèles ;
(2) L'utilisation de modèles pour observer les systèmes logiciels peut rester au niveau de la conception sans être bloquée sur des détails triviaux d'objets
(3) Les équipes n'utilisent pas facilement des modèles de conception pour communiquer et partager leurs opinions ; mal compris.
Auteur : Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, plus tard connu sous le nom de « Gang » des Quatre, GoF). Il y a deux livres :
Lecture hautement recommandée. Le titre anglais est « Head First Design Patterns ».
Tous ceux qui croient en Jésus doivent lire la Bible, et tous ceux qui croient en OO (orienté objet) doivent lire "Head First Design Patterns" du quatuor, le site officiel Head First Design Patterns. 2004 Le livre remporte le Jolt Award (semblable aux Oscars dans le domaine du cinéma).
est le héros qui a classé les modèles pour la première fois, démarrant un grand pas en avant dans le domaine des logiciels
Modèle de modèle : y compris le nom ; , classe Objectif, intention, motivation, applicabilité, diagramme de classe, participants et leur collaboration, résultats, mise en œuvre, exemple de code, applications connues, modèles associés, etc.
Le titre anglais est « Modèles de conception : éléments de logiciels orientés objet réutilisables » . Également écrit par le quatuor.
est un livre sur la conception de logiciels dans le domaine du génie logiciel. Il propose et résume des solutions standard à certains problèmes courants de conception de logiciels, appelés modèles de conception de logiciels. Ce livre a été publié pour la première fois le 21 octobre 1994 et avait été imprimé à 40 exemplaires en mars 2012.
Les modèles de conception peuvent être divisés en trois grandes catégories, et chaque catégorie contient un certain nombre de modèles spécifiques.
Plusieurs modèles qui se confondent facilement : usine simple S / usine abstraite A / méthode factory F / méthode template T
Ceux avec le mot "factory" : ne servent qu'à créer des instances, telles que S/A/F ; sans limitation, telles que T ;
"Méthode" : celles avec le mot "méthode" ne nécessitent pas de participation supplémentaire du client et peuvent fonctionner indépendamment, comme F/T ; sans cela, des appels clients supplémentaires, tels que S/A sont nécessaires ;
est utilisé pour la création d'objets. Placez le travail de création d'un objet dans un autre objet ou reportez-le à une sous-classe.
Assurez-vous qu'une classe n'a qu'une seule instance et fournissez un point d'accès global.
Il convient de noter que l'utilisation d'un singleton sous plusieurs chargeurs de classe entraînera une instance singleton sous chaque type de chargeur, car chaque chargeur de classe a son propre espace de noms indépendant.
Les singletons du JDK incluent Runtime.getRuntime()
, NumberFormat.getInstance()
Ce qui suit résume quatre méthodes d'implémentation Java thread-safe. Chaque implémentation peut être appelée avec Singleton.getInstance().method();
.
Idée clé : En tant que variable globale statique de la classe, elle est instanciée lorsque la classe est chargée.
L'inconvénient est que l'instance a été instanciée avant d'être réellement utilisée (ou peut ne pas être utilisée du tout), ce qui constitue un gaspillage de ressources.
Pour Hotspot VM, si cette classe n'est pas impliquée, elle est en fait instanciée lorsque getInstance() est appelée pour la première fois.
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } // 基于 classLoader 机制,自动达到了线程安全的效果 public static Singleton getInstance() { return instance; } public void method() { System.out.println("method() OK."); } }
Idée clé : réaliser une synchronisation sur la méthode getInstance().
L'inconvénient est qu'à chaque fois que getInstance() est appelé, un verrou sera verrouillé, mais en fait il n'est requis que pour la première instanciation ultérieure. Le verrouillage est un gaspillage, entraînant une baisse significative des performances.
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private static Singleton instance = null; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } public void method() { System.out.println("method() OK."); } }
Idée clé : Vérifiez qu'il n'a pas encore été créé lorsqu'il est désynchronisé, puis instanciez-le lorsqu'il est synchronisé et vérifiez qu'il n'a pas été instancié. Afin de réduire considérablement les situations de synchronisation.
L'inconvénient est que JDK5+ est requis, sinon de nombreuses implémentations JVM de volatile entraîneront l'échec du double verrouillage. Cependant, très peu de développeurs utilisent désormais JDK5, cette lacune n’est donc pas pertinente.
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private volatile static Singleton instance = null; // 注意 volatile private Singleton() { } public static Singleton getInstance() { if (instance == null) { // 初步检查:尚未实例化 synchronized (Singleton.class) { // 再次同步(对 Singleton.class) if (instance == null) { // 确认尚未实例化 instance = new Singleton(); } } } return instance; } public void method() { System.out.println("method() OK."); } }
Idée clé : les membres statiques globaux sont placés dans des classes internes et sont instanciés uniquement lorsque la classe interne est référencée. but de l’instanciation retardée. C'est une solution parfaite :
Assure une instanciation retardée de l'appel à getInstance()
Aucun verrouillage requis, bonnes performances <🎜 ; >
/** * @author: kefeng.wang * @date: 2016-06-07 10:21 **/public class Singleton { private static class InstanceHolder { // 延迟加载实例 private static Singleton instance = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return InstanceHolder.instance; } public void method() { System.out.println("method() OK."); } }
Veuillez vous référer au code source de
pour l'implémentation Java. Voici ses effets d'utilisation : StringBuilder
StringBuilder sb = new StringBuilder(); sb.append("Hello world!").append(123).append('!'); System.out.println(sb.toString());
, Boolean.valueOf(String)
dans JDK. Class.forName(String)
/** * @author: kefeng.wang * @date: 2016-06-09 19:42 **/public class DPC3_SimpleFactoryPattern { private static class SimpleFactory { public CommonProduct createProduct(int type) { // 工厂方法,返回“产品”接口,形参可无 if (type == 1) { return new CommonProductImplA(); // 产品具体类 } else if (type == 2) { return new CommonProductImplB(); } else if (type == 3) { return new CommonProductImplC(); } else { return null; } } } private static class SimpleFactoryClient { private SimpleFactory factory = null; public SimpleFactoryClient(SimpleFactory factory) { this.factory = factory; } public final void run() { CommonProduct commonProduct1 = factory.createProduct(1); CommonProduct commonProduct2 = factory.createProduct(2); CommonProduct commonProduct3 = factory.createProduct(3); System.out.println(commonProduct1 + ", " + commonProduct2 + ", " + commonProduct3); } } public static void main(String[] args) { SimpleFactory factory = new SimpleFactory(); // 工厂实例 new SimpleFactoryClient(factory).run(); // 传入客户类 } }
Le client sélectionne de manière flexible la classe d'implémentation pour terminer la création de l'objet.
Ce mode est utilisé dans JDK avec
. NumberFormat.getInstance()
La différence est : ce mode ne nécessite pas de client, et ses propres méthodes peuvent effectuer les opérations avant et après la création de l'objet.
de Java. Object.clone()
Utilisés pour les relations de combinaison de classes ou d'objets.
Adapter une interface à une autre interface souhaitée peut éliminer les problèmes de compatibilité causés par une incompatibilité d'interface.
Par exemple, adaptez Enumeration<E>
à Iterator<E>
, et Arrays.asList()
adaptez T[]
à List<T>
.
Les choses sont composées de plusieurs facteurs, et chaque facteur a une classe abstraite et plusieurs classes d'implémentation. En fin de compte, ces multiples facteurs peuvent être combinés librement.
Par exemple, une variété de télécommandes + une variété de téléviseurs, une variété de modèles de voitures + une variété de conditions routières + une variété de conducteurs. JDBC
et AWT
dans le JDK.
Organiser la "partie/tout" de l'objet dans une arborescence afin qu'un seul objet ou une combinaison de plusieurs objets puisse être traité uniformément.
Tels que les menus à plusieurs niveaux, les arbres binaires, etc.
Attachez dynamiquement des responsabilités aux décorateurs au moment de l'exécution.
Il existe deux manières d'étendre les fonctions. L'héritage de classe est déterminé statiquement au moment de la compilation, tandis que le mode décorateur est déterminé dynamiquement au moment de l'exécution, ce qui présente des avantages uniques.
Par exemple, une fois que StringReader
est décoré de LineNumberReader
, les interfaces associées line
sont étendues pour le flux de caractères.
fournit une interface de haut niveau unifiée pour accéder à un groupe d'interfaces dans le sous-système, rendant le sous-système plus facile à utiliser.
Par exemple, pour démarrer (ou arrêter) un ordinateur, il appelle les interfaces de démarrage (ou d'arrêt) respectives du CPU/mémoire/disque.
Utilisez la technologie de partage pour prendre en charge efficacement un grand nombre d'objets à granularité fine.
Par exemple, un traitement de texte n'a pas besoin de générer plusieurs objets glyphes pour plusieurs occurrences de chaque caractère. Au lieu de cela, plusieurs occurrences du même caractère dans une structure de données externe partagent un seul objet glyphe. Integer.valueOf(int)
dans JDK adopte ce mode.
Le proxy crée et conserve une référence au sujet lorsque le client appelle le proxy, le proxy la transmettra au sujet.
Par exemple, Collections
vue de collection, appel à distance RMI/RPC, proxy de cache, proxy de pare-feu, etc. en Java.
est utilisé pour la relation d'appel de classes ou d'objets.
Une demande est transmise le long d'une chaîne jusqu'à ce qu'un processeur sur la chaîne la traite.
Par exemple, les filtres dans SpringMVC.
Encapsuler la commande en tant qu'objet, qui peut être stocké/chargé, transféré, exécuté/annulé, mis en file d'attente, enregistré, etc., et le "demandeur de l'action" Découplage de "l'exécuteur de l'action".
Les participants incluent Invoker (appelant) => Command (commande) => Receiver (exécuteur).
Telles que les tâches planifiées et les tâches de fil Runnable
.
est utilisé pour créer un interpréteur de langage simple capable de gérer les langages de script et les langages de programmation, en créant une classe pour chaque règle.
Par exemple, java.util.Pattern
, java.text.Format
dans JDK.
Fournit une méthode pour accéder séquentiellement aux éléments individuels d'un objet agrégé sans exposer sa représentation interne.
Tels que java.util.Iterator
et java.util.Enumeration
dans JDK.
Utilisez un objet médiateur pour encapsuler une série d'interactions d'objets. L'objet médiateur élimine le besoin pour les objets de se référencer explicitement les uns les autres, desserrant ainsi leur couplage et l'interaction entre eux. ils peuvent être modifiés indépendamment.
Tels que java.util.Timer
et java.util.concurrent.ExecutorService.submit()
dans JDK.
L'objet mémento est utilisé pour stocker un instantané de l'état interne d'un autre objet, et peut être stocké en externe et peut être restauré à son état d'origine ultérieurement. Comme la sérialisation Java.
Tels que java.util.Date
et java.io.Serializable
dans JDK.
Dépendance un-à-plusieurs entre les objets Lorsque l'état de l'objet observé change, l'observateur sera averti.
Les participants incluent Observable/Observer.
Comme les événements en RMI, java.util.EventListener
.
Lorsque l'état interne d'un objet change, son comportement change également. Son implémentation interne consiste à définir une classe parent d'état et à étendre la sous-classe d'état pour chaque état. Lorsque l'état interne de l'objet change, la sous-classe d'état sélectionnée change également, mais l'extérieur n'a besoin que d'interagir avec l'objet et ne le sait pas. existence de sous-classes d’État.
Par exemple, l'état d'arrêt/lecture/pause du lecteur vidéo.
Définir un ensemble d'algorithmes, qui sont encapsulés séparément et indépendants des clients. Lorsque l'algorithme est modifié, cela n'affecte pas l'utilisation du client.
Par exemple, différents personnages du jeu peuvent utiliser divers équipements, et ces équipements peuvent être emballés de manière stratégique.
Tel que java.util.Comparator#compare()
dans JDK.
La classe abstraite définit le cadre logique de niveau supérieur (appelé "méthode modèle"), et certaines étapes (peuvent créer des instances ou d'autres opérations) sont retardées à l'implémentation de sous-classe, il peut fonctionner indépendamment.
Lorsque l'opération implémentée par la sous-classe consiste à créer une instance, la méthode modèle devient le modèle de méthode d'usine, la méthode d'usine est donc une méthode de modèle spéciale.
Sans modifier la structure des données du visiteur, le visiteur encapsule l'opération d'accès. Le point clé est que le visiteur fournit l'interface consultée.
Le scénario applicable est que les visiteurs sont stables mais que les visiteurs sont flexibles, ou que les visiteurs ont de nombreux types d'opérations différents.
Combinez deux modes ou plus pour former une solution permettant de résoudre les problèmes courants qui surviennent souvent.
Cas d'utilisation : modèle MVC (Modèle/Vue/Contrôleur), utilisant Observer, Strategy, Composite, Factory, Decorator et d'autres modèles.
Cas d'utilisation : Appareils électroménagers = interface + données + contrôle logique, centre commercial = magasin + entrepôt + contrôle logique.
Wikipedia : Modèles de conception
Wikipédia : Modèle de conception de logiciels
TutorialsPoint : Modèle de conception
Les modèles de conception sont des situations spécifiques qui surviennent constamment Ci-dessous, des modèles de solutions spécifiques (routines) qui peuvent être utilisés à plusieurs reprises pour des problèmes spécifiques. Cet article résume les points clés de l'utilisation de 24 modèles de conception courants selon les trois catégories de création, de structure et de comportement, y compris les scénarios et solutions applicables et leurs implémentations Java correspondantes.
Articles connexes :
Explication détaillée des modèles de conception Java courants - Modèle d'usine
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!