Il est très difficile de rendre un logiciel très flexible et facile à maintenir. Les logiciels flexibles ont une structure complexe et sont difficiles à maintenir. Il y a des gains et des pertes, et la clé réside dans la manière de gérer les deux afin que les pertes l’emportent sur les pertes. La conception et le développement du logiciel doivent suivre les six principes suivants : 1. OCP Nom complet : « Principe ouvert-fermé » Principe ouvert-fermé Description : Ouvert pour extension, fermé pour modification. Avantages : Le système conçu selon les principes OCP réduit le couplage entre les différentes parties du programme, et son adaptabilité, sa flexibilité et sa stabilité sont relativement bonnes. Lorsque de nouvelles fonctions doivent être ajoutées à un système logiciel existant, il n'est pas nécessaire de modifier la couche d'abstraction qui constitue la base du système. Seuls de nouveaux modules doivent être ajoutés à la base d'origine pour réaliser les fonctions qui doivent être ajoutées. . Les nouveaux modules ajoutés n'ont pas ou très peu d'impact sur les modules d'origine, il n'est donc pas nécessaire de retester les modules d'origine. Comment implémenter le principe "ouvert-fermé" Dans la conception orientée objet, ce qui n'est pas autorisé à changer est la couche d'abstraction du système, mais ce qui peut être étendu est la couche d'implémentation du système . En d’autres termes, définissez une couche de conception d’abstraction une fois pour toutes qui permet d’implémenter autant de comportements que possible au niveau de la couche d’implémentation. La clé pour résoudre les problèmes réside dans l’abstraction, qui est la première essence de la conception orientée objet. Abstraire quelque chose, c'est essentiellement résumer son essence. L'abstraction nous permet de saisir les choses les plus importantes et de penser à un niveau supérieur. Cela réduit la complexité de la réflexion et nous n’avons pas besoin de penser à tant de choses en même temps. En d’autres termes, nous encapsulons l’essence des choses et ne pouvons voir aucun détail. Dans la programmation orientée objet, à travers les classes abstraites et les interfaces, les caractéristiques des classes concrètes sont stipulées comme une couche d'abstraction, qui est relativement stable et n'a pas besoin d'être modifiée, satisfaisant ainsi l'exigence d'être « fermée à la modification » tandis que les classes concrètes dérivées de classes abstraites peuvent être modifiées. Le comportement du système afin qu'il satisfasse à "l'ouverture à l'extension". Lors de l'extension de l'entité, il n'est pas nécessaire de modifier le code source ou le code binaire du logiciel. La clé est l’abstraction.
2. LSP Nom complet : "Principe de substitution de Liskov" Principe de substitution de Liskov Remarque : le sous-type doit être capable de remplacer leurs types de base. Si une entité logicielle utilise une classe de base, lorsque la classe de base est remplacée par une sous-classe qui hérite de la classe de base, le comportement du programme ne changera pas. Les entités logicielles ne connaissent pas la différence entre les objets de classe de base et les objets de sous-classe. Avantages : Il est facile de réaliser l'échange de sous-classes sous la même classe parent sans que le client s'en rende compte.
3. DIP Nom complet : "Principe d'inversion de dépendance" Principe d'inversion de dépendance Explication : Dépend de l'abstraction, pas du concret. Les clients s'appuient sur un couplage abstrait. L'abstraction ne devrait pas dépendre des détails ; les détails devraient dépendre de l'abstraction ; La programmation devrait être destinée aux interfaces, pas à l'implémentation ; Avantages : En utilisant les dépendances créées par la programmation procédurale traditionnelle, la stratégie dépend des détails, ce qui est mauvais car la stratégie est affectée par les changements dans les détails. Le principe d'inversion de dépendance rend les détails et les stratégies dépendants de l'abstraction, et la stabilité de l'abstraction détermine la stabilité du système. Comment réaliser l’inversion des dépendances ? Le couplage de manière abstraite est la clé du principe d'inversion de dépendance. Les relations de couplage abstraites impliquent toujours des classes concrètes héritant de classes abstraites, et il est nécessaire de garantir que toute référence à la classe de base puisse être modifiée en sa sous-classe. Par conséquent, le principe de substitution de Liskov est la base du principe d'inversion de dépendance. Bien que le couplage au niveau abstrait soit flexible, il apporte également une complexité supplémentaire. Si la possibilité de changement de classe spécifique est très faible, alors les avantages du couplage abstrait seront très limités. mieux vaut utiliser un couplage en béton. Hiérarchie : toutes les architectures orientées objet bien structurées ont des définitions de couches claires, et chaque couche fournit un ensemble de services cohérents vers l'extérieur via une interface bien définie et contrôlée. Dépend de l'abstraction : il est recommandé de ne pas s'appuyer sur des classes concrètes, c'est-à-dire que toutes les dépendances du programme doivent se terminer par des classes ou des interfaces abstraites. Essayez de faire ce qui suit : 1. Aucune variable ne doit contenir un pointeur ou une référence à une classe spécifique. 2. Aucune classe ne doit être dérivée d'une classe concrète. 3. Aucune méthode ne doit remplacer la méthode implémentée dans aucune de ses classes de base.
4. FAI Nom complet : "Principe de ségrégation des interfaces" Principe d'isolation des interfaces Explication : Il est toujours préférable d'utiliser plusieurs interfaces de fonctions dédiées plutôt que d'utiliser une seule interface totale. . Du point de vue d'une classe client : la dépendance d'une classe par rapport à une autre classe doit être basée sur l'interface minimale. Une interface trop pléthorique est une pollution de l’interface et ne doit pas obliger les clients à s’appuyer sur des méthodes qu’ils n’utilisent pas. Avantages : Lorsqu'une fonction d'un système logiciel est étendue, la pression de modification ne sera pas transmise aux autres objets. Comment mettre en œuvre le principe d'isolation des interfaces Les utilisateurs ne devraient pas être obligés de s’appuyer sur des méthodes qu’ils n’utilisent pas. 1. Utilisez la délégation pour séparer les interfaces. 2. Utilisez l'héritage multiple pour séparer les interfaces. 5. CARP ou CRP Nom complet : « Compositee/Principe de réutilisation des agrégats » Principe de réutilisation de la synthèse/agrégation ou « Principe de réutilisation composite"Principe de réutilisation composite Remarque : Si certaines fonctions du nouvel objet ont été implémentées dans d'autres objets déjà créés, essayez d'utiliser d'autres objets Fournissez des fonctionnalités pour qu'il devient partie intégrante du nouvel objet plutôt que de le recréer vous-même. Les nouveaux objets permettent de réutiliser les fonctionnalités existantes en déléguant à ces objets. En bref, essayez d'utiliser la composition/agrégation et essayez de ne pas utiliser l'héritage. Avantages : 1) Le seul moyen pour un nouvel objet d'accéder aux objets composants est via l'interface de l'objet composant. 2) Ce type de réutilisation est une réutilisation en boîte noire, car les détails internes des objets composants sont invisibles pour le nouvel objet. 3) Ce type de réutilisation soutient les emballages. 4) Ce type de réutilisation nécessite moins de dépendances. 5) Chaque nouvelle classe peut se concentrer sur une tâche. 6) Ce type de réutilisation peut être effectué dynamiquement pendant l'exécution, et les nouveaux objets peuvent référencer dynamiquement des objets du même type que les objets composants. 7) En tant que méthode de réutilisation, elle peut être appliquée à presque tous les environnements. Inconvénients : Autrement dit, il y aura plus d'objets dans le système qui devront être gérés.
6. LOD ou LKP Nom complet : « Loi de Déméter » Principe de Déméter ou « Principe de moindre connaissance » Principe de moindre connaissance Explication : Les objets doivent être liés le moins de manières possible pour éviter des relations inextricables. Comment mettre en œuvre la loi de Déméter L'objectif principal de la loi de Déméter est de contrôler la surcharge d'informations Lorsque vous l'appliquez à la conception du système, vous devez faire attention aux points suivants : 1) En termes de classe. division, les classes doivent être créées avec un couplage faible. Plus le couplage entre classes est faible, plus il est facile de les réutiliser. 2) En termes de conception de la structure des classes, chaque classe doit minimiser les droits d'accès des membres. Une classe ne doit pas rendre ses propriétés publiques, mais doit fournir des méthodes pour obtenir et attribuer des valeurs afin de permettre au monde extérieur d'accéder indirectement à ses propriétés. 3) Dans la conception de classe, dans la mesure du possible, une classe doit être conçue pour être une classe immuable. 4) En termes de références à d'autres objets, les références d'une classe à d'autres objets doivent être minimisées.
Il existe également un principe de responsabilité unique :
SRP--Principe de responsabilité unique) : en ce qui concerne une classe, elle ne doit se concentrer que sur Faites une chose et n'ayez qu'une seule raison pour que cela change . Les soi-disant responsabilités peuvent être comprises comme des fonctions, c'est-à-dire que la fonction conçue ne doit avoir qu'une seule fonction, et non deux ou plus. Cela peut également être compris comme la raison du changement de référence. Lorsque vous constatez qu'il y a deux changements qui nous obligeront à modifier cette classe, vous devriez alors envisager de retirer cette classe. La responsabilité étant un axe de changement, lorsque les exigences changent, le changement reflétera l'évolution des responsabilités de la classe. Points à noter lors de l'utilisation du SRP : 1. Une classe raisonnable ne devrait avoir qu'une seule raison pour son changement, c'est-à-dire une seule responsabilité 2. Il n'est pas judicieux d'appliquer le SRP ou d'autres principes sans signes de changement ; 3. Lorsque les exigences changent réellement, des principes tels que SRP doivent être appliqués pour refactoriser le code ; 4. L'utilisation du développement piloté par les tests nous obligera à séparer le code déraisonnable avant que la conception ne sente 5. Si vous ne pouvez pas forcer la séparation des responsabilités, l'odeur de rigidité et de fragilité deviendra très forte, alors vous devez utiliser le mode Façade ou Proxy pour refactoriser le code ; avantages SRP : éliminer le couplage et réduire la rigidité du code causée par les changements d'exigences.
Vous n'êtes pas obligé d'adhérer strictement à ces principes, et il n'y a aucune sanction religieuse en cas de violation. Mais vous devez considérer ces principes comme une sonnette d’alarme. Si l’un d’entre eux est violé, la sonnette d’alarme retentit. -----Arthur J.Riel (1) Toutes les données doivent être cachées à l'intérieur de la classe où elles se trouvent. (2) Les utilisateurs d'une classe doivent s'appuyer sur l'interface partagée de la classe, mais une classe ne peut pas s'appuyer sur ses utilisateurs. p15 (3) Minimiser les messages dans le protocole de classe. (4) Implémentez l'interface publique la plus élémentaire que toutes les classes comprennent [par exemple, les opérations de copie (copie profonde et copie superficielle), le jugement d'égalité, le contenu de sortie correct, l'analyse à partir de la description ASCII, etc.]. p16 (5) Ne mettez pas les détails d'implémentation (tels que les fonctions privées qui placent du code partagé) dans l'interface publique de la classe. Si deux méthodes d'une classe ont un code commun, alors vous pouvez créer une fonction privée qui empêche ces codes communs. (6) Ne perturbez pas l'interface publique d'une classe avec des éléments que les utilisateurs ne peuvent pas utiliser ou qui ne les intéressent pas. p17 (7) Il ne devrait y avoir aucun couplage entre les classes, ou uniquement des relations de couplage dérivées. Autrement dit, soit une classe n'a rien à voir avec une autre classe, soit elle utilise uniquement des opérations dans l'interface publique d'une autre classe. p18 (8) Les classes ne doivent représenter qu'une seule abstraction clé. Toutes les classes du package doivent être fermées conjointement pour les modifications du même type de propriétés. Si un changement affecte un package, il affectera toutes les classes du package, mais n'aura aucun impact sur les autres packages (9) Centraliser les données et les comportements associés. Les concepteurs doivent prêter attention aux objets qui obtiennent des données d'autres objets via des opérations telles que get. Ce type de comportement implique que ce principe empirique est violé. (10) Mettez les informations non pertinentes dans une autre classe (c'est-à-dire le comportement de ne pas communiquer entre eux). p19 Évoluez vers des dépendances stables (11) Assurez-vous que le concept abstrait que vous modélisez est une classe, pas seulement le rôle joué par un objet. p23 (12) Répartir les fonctions du système aussi uniformément que possible dans le sens horizontal, c'est-à-dire : selon la conception, les classes de niveau supérieur doivent partager le travail de manière uniforme. (13) Ne créez pas de classes/objets omnipotents dans votre système. Soyez particulièrement prudent avec les classes dont les noms incluent Driver, Manager, System et Susystem. Planifier une interface plutôt que mettre en œuvre une interface. (14) Soyez prudent avec les classes qui définissent un grand nombre de méthodes d'accès dans l'interface publique. Le grand nombre de méthodes d’accès signifie que les données et comportements pertinents ne sont pas stockés de manière centralisée. (15) Attention aux cours qui contiennent trop de comportements qui ne communiquent pas entre eux. Une autre manifestation de ce problème est la création de nombreuses fonctions get et set dans l'interface publique de la classe de votre application. (16) Dans une application composée d'un modèle orienté objet qui interagit avec l'interface utilisateur, le modèle ne doit pas dépendre de l'interface, mais l'interface doit dépendre du modèle. (17) Modéliser autant que possible en fonction du monde réel (nous violons souvent ce principe afin de respecter le principe de distribution des fonctions du système, d'éviter le principe de classe polyvalent et de placer de manière centralisée les données et les comportements associés) . (18) Supprimez les classes inutiles de votre conception. De manière générale, nous déclasserons cette classe en propriété. (19) Supprimer les classes en dehors du système. La caractéristique des classes extérieures au système est que, en termes abstraits, elles envoient uniquement des messages au domaine système mais n'acceptent pas les messages des autres classes du domaine système. (20)Ne transformez pas les opérations en cours. Interrogez toute classe dont le nom est un verbe ou dérivé d'un verbe, en particulier une classe avec une seule action significative. Déterminez si ce comportement significatif doit être déplacé vers une classe qui existe déjà ou qui n’a pas encore été découverte. (21) Nous introduisons souvent des classes proxy lors de la création de modèles d'analyse d'applications. Lors de la phase de conception, nous constatons souvent que de nombreux agents sont inutiles et doivent être supprimés. (22) Essayez de réduire le nombre de collaborateurs d'une classe. Le nombre d'autres classes utilisées par une classe doit être aussi réduit que possible. (23) Minimisez le nombre de messages transmis entre les classes et les collaborateurs. (24) Minimiser la quantité de collaboration entre les classes et les collaborateurs, c'est-à-dire : réduire le nombre de messages différents transmis entre les classes et les collaborateurs. (25) Minimiser la diffusion de la classe, c'est-à-dire : réduire le produit du nombre de messages définis par la classe et du nombre de messages envoyés (26) Si la classe contient des objets d'une autre classe , alors la classe conteneur doit être L'objet contenu envoie le message. Autrement dit : une relation d’inclusion implique toujours une relation d’usage. (27) La plupart des méthodes définies dans une classe doivent utiliser la plupart des données membres la plupart du temps.
(28) Le nombre d'objets contenus dans une classe ne doit pas dépasser la capacité de la mémoire à court terme du développeur. Ce nombre est souvent 6. Lorsqu'une classe contient plus de 6 données membres, vous pouvez diviser les données membres logiquement liées en un groupe, puis utiliser une nouvelle classe conteneur pour contenir ce groupe de membres. (29) Laissez les fonctions du système être distribuées verticalement dans un système d'héritage étroit et profond. (30) Lors de l'implémentation de contraintes sémantiques, il est préférable de les implémenter en fonction des définitions de classe. Cela conduit souvent à un débordement de classe, auquel cas les contraintes doivent être implémentées dans le comportement de la classe, généralement mais pas nécessairement dans le constructeur. (31) Lors de l'implémentation de contraintes sémantiques dans le constructeur d'une classe, placez le test de contrainte dans le niveau d'inclusion le plus profond autorisé par le champ constructeur. (32) Si les informations sémantiques sur lesquelles s'appuient les contraintes changent fréquemment, alors il est préférable de les placer dans un objet tiers centralisé. (33) Si les informations sémantiques sur lesquelles s'appuient les contraintes changent rarement, alors. il est mieux réparti entre les différentes classes impliquées dans les contraintes. (34)Une classe doit savoir ce qu'elle contient, mais elle ne peut pas savoir qui le contient. (35) Les objets qui partagent une portée littérale (c'est-à-dire contenus dans la même classe) ne doivent pas avoir de relation d'utilisation les uns avec les autres. (36) L'héritage ne doit être utilisé que pour modéliser des hiérarchies de spécialisation. (37) Les classes dérivées doivent connaître la classe de base, et les classes de base ne doivent connaître aucune information sur leurs classes dérivées. (38) Toutes les données de la classe de base doivent être privées, n'utilisez pas de données protégées.
Les concepteurs de classe ne devraient jamais placer dans des interfaces publiques des éléments dont les utilisateurs de la classe n'ont pas besoin. (39) En théorie, la hiérarchie d'héritage devrait être plus profonde, plus c'est profond, mieux c'est. (40)En pratique, la profondeur de la hiérarchie successorale ne doit pas dépasser la capacité de mémoire à court terme d'une personne moyenne. Une valeur de profondeur largement acceptée est 6 (41) Toutes les classes abstraites doivent être des classes de base (42) Toutes les classes de base doivent être des classes abstraites (43) Placez les points communs dans les données, les comportements et/ou les interfaces aussi haut que possible dans la hiérarchie d'héritage. (44) Si deux classes ou plus partagent des données communes (mais aucun comportement commun), alors les données communes doivent être placées dans une classe, et chaque classe qui partage ces données contient cette classe. (45) Si deux classes ou plus ont des données et un comportement communs (c'est-à-dire des méthodes), alors chacune de ces classes doit hériter d'une classe de base commune qui représente ces données et méthodes. (46) Si deux classes ou plus partagent une interface commune (faisant référence à des messages et non à des méthodes), elles ne devraient alors hériter d'une classe de base commune que si elles doivent être utilisées de manière polymorphe. (47) L'analyse au cas par cas de l'affichage des types d'objets est généralement erronée. Dans la plupart de ces cas, les concepteurs doivent utiliser le polymorphisme. (48) L'analyse au cas par cas de l'affichage des valeurs d'attribut est souvent erronée. Les classes doivent être découplées dans une hiérarchie d'héritage, chaque valeur d'attribut étant transformée en classe dérivée.
(49) Ne modélisez pas la sémantique dynamique d'une classe à travers des relations d'héritage. Tenter de modéliser une sémantique dynamique avec des relations sémantiques statiques entraîne un changement de type au moment de l'exécution. (50)Ne transformez pas les objets de classe en classes dérivées. Soyez prudent avec toute classe dérivée qui n'a qu'une seule instance. (51) Si vous pensez que vous devez créer une nouvelle classe au moment de l'exécution, prenez du recul et réalisez que vous créez des objets. Maintenant, généralisons ces objets dans une classe. (52) Il devrait être illégal d'utiliser une méthode vide (c'est-à-dire une méthode qui ne fait rien) dans une classe dérivée pour remplacer une méthode dans la classe de base. (53) Ne confondez pas l’inclusion facultative avec la nécessité d’un héritage. La modélisation de l'inclusion facultative comme héritage conduit à une prolifération de classes. (54) Lors de la création de hiérarchies d'héritage, essayez de créer des frameworks réutilisables plutôt que des composants réutilisables. (55) Si vous utilisez l'héritage multiple dans votre conception, supposez que vous avez commis une erreur. Si vous n’avez pas commis d’erreur, vous devez essayer de le prouver. (56) Tant que l'héritage est utilisé dans la conception orientée objet, posez-vous deux questions : (1) La classe dérivée est-elle un type spécial de la chose dont elle hérite ? (2) La classe de base fait-elle partie de la classe dérivée ? (57) Si vous trouvez plusieurs relations d'héritage dans une conception orientée objet, assurez-vous qu'aucune classe de base n'est en réalité une classe dérivée d'une autre classe de base. (58) Dans la conception orientée objet, si vous devez choisir entre l'inclusion et l'association, veuillez choisir l'inclusion. (59) N'utilisez pas de données globales ou de fonctions globales pour la comptabilité des objets de classe. Des variables de classe ou des méthodes de classe doivent être utilisées. (60) Les concepteurs orientés objet ne devraient pas laisser les principes de conception physique miner leurs conceptions logiques. Cependant, nous utilisons souvent des critères de conception physique pour prendre des décisions concernant la conception logique. (61) Ne contournez pas l'interface publique pour modifier l'état de l'objet.
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!
Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn