


MODÈLES DE CONCEPTION : Une plongée approfondie dans les modèles de conception courants
Qu’est-ce qu’un modèle de conception ?
Les modèles de conception sont des solutions à des problèmes complexes. Les modèles de conception consistent à créer vos classes et interfaces de manière à résoudre un problème de conception particulier. Habituellement, lors de la conception d’un système, nous rencontrons certains problèmes, et pour ces problèmes, nous disposons d’un ensemble de modèles de conception. Les modèles de conception sont généralement des modèles qui impliquent des classes, des interfaces et les relations entre ces classes.
Types de modèles de conception :
Modèles de conception créationnels :
Ces types de modèles traitent de la création d'objets d'une manière compatible avec la situation donnée.
Au niveau créationnel, nous pouvons déterminer comment des parties spécifiques de nos systèmes peuvent être créées indépendamment ou composées ensemble, garantissant flexibilité et compatibilité.
La liste des modèles de conception qui entrent dans cette catégorie est :
- Singleton : Dans ce modèle de conception, nous n'avons qu'une seule instance et cette instance sera utilisée dans toute notre application.
Essentiels du modèle de conception singleton :
- Constructeur privé : Marquer le constructeur comme privé est très crucial, car nous voulons nous assurer qu'une seule instance de la classe est créée.
- Instance statique privée : Nous utilisons un modificateur d'accès privé, car nous voulons nous assurer que nous n'avons qu'une seule instance de l'objet dans la mémoire de la classe.
- Méthode statique publique (accesseur) : Il s'agit d'un point d'accès global à l'instance unique. Cette méthode crée essentiellement l'instance si elle n'existe pas, sinon renvoie la même instance si elle existe déjà.
Exemple de modèle de conception Singleton
public class Singleton { // Private static instance of the class private static Singleton instance; private int count; // Private constructor to prevent instantiation private Singleton() { // initialization code } // Public static method to provide access to the instance public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } // Example method public void getCount() { System.out.println("The value of count is: " + count); } public void increaseCount() { count++; } public void decreaseCount() { count--; } } public class Main { public static void main(String[] args) { // Get the single instance of Singleton Singleton singleton = Singleton.getInstance(); singleton.increaseCount(); singleton.getCount(); // Output: The value of count is: 1 // Get the same instance of Singleton Singleton anotherSingleton = Singleton.getInstance(); anotherSingleton.decreaseCount(); anotherSingleton.getCount(); // Output: The value of count is: 0 // Both singleton and anotherSingleton refer to the same instance } }
- Builder : Dans le modèle Builder, nous définissons une manière de créer un objet étape par étape. Ce modèle offre également de la flexibilité, permettant de créer différentes versions du même objet en utilisant le même processus de construction.
Les éléments essentiels du modèle de constructeur :
- Produit :C'est l'objet complexe qui est en cours de construction.
- Interface Builder : Définit les méthodes pour créer différentes parties du produit. Ces méthodes renvoient généralement l'objet constructeur lui-même pour permettre le chaînage de méthodes.
- Concrete Builder : Implémente l'interface Builder et fournit des implémentations spécifiques pour créer des parties du produit.
Exemple de modèle de constructeur :
Cet exemple montre comment utiliser le Builder Design Pattern pour préparer un pain à tartiner au chocolat en ajoutant des ingrédients étape par étape.
// Product Class class Bread { private String bread; private String spread; private String chiaSeeds; private String pumpkinSeeds; public void setBread(String bread) { this.bread = bread; } public void setSpread(String spread) { this.spread = spread; } public void setChiaSeeds(String chiaSeeds) { this.chiaSeeds = chiaSeeds; } public void setPumpkinSeeds(String pumpkinSeeds) { this.pumpkinSeeds = pumpkinSeeds; } @Override public String toString() { return "Bread with " + spread + ", topped with " + chiaSeeds + " and " + pumpkinSeeds; } } // Builder Interface interface BreadBuilder { BreadBuilder addBread(); BreadBuilder addChocolateSpread(); BreadBuilder addChiaSeeds(); BreadBuilder addPumpkinSeeds(); Bread build(); } // Concrete Builder class ChocolateBreadBuilder implements BreadBuilder { private Bread bread = new Bread(); @Override public BreadBuilder addBread() { bread.setBread("Whole grain bread"); return this; } @Override public BreadBuilder addChocolateSpread() { bread.setSpread("Chocolate spread"); return this; } @Override public BreadBuilder addChiaSeeds() { bread.setChiaSeeds("Chia seeds"); return this; } @Override public BreadBuilder addPumpkinSeeds() { bread.setPumpkinSeeds("Pumpkin seeds"); return this; } @Override public Bread build() { return bread; } } // Client Code public class Main { public static void main(String[] args) { // Create a builder and build the chocolate spread bread BreadBuilder builder = new ChocolateBreadBuilder(); Bread myBread = builder.addBread() .addChocolateSpread() .addChiaSeeds() .addPumpkinSeeds() .build(); // Output the result System.out.println(myBread); } }
- Méthode Factory : Dans le modèle Factory Method, nous définissons une manière de créer des objets, mais nous autorisons les sous-classes à décider du type spécifique d'objet qui sera créé.
Les éléments essentiels du modèle d'usine :
- Interface produit : Définit l'interface commune à tous les produits.
- Produits en béton : Implémentez l'interface Produit.
- Créateur : Déclare la méthode d'usine.
- Créateurs de béton : Implémentez la méthode de l'usine pour retourner différents produits en béton.
// Product Interface interface Juice { void serve(); } // Concrete Product 1 class OrangeJuice implements Juice { @Override public void serve() { System.out.println("Serving Orange Juice."); } } // Concrete Product 2 class MangoJuice implements Juice { @Override public void serve() { System.out.println("Serving Mango Juice."); } } // Creator Abstract Class abstract class JuiceFactory { // Factory method public abstract Juice createJuice(); } // Concrete Creator 1 class OrangeJuiceFactory extends JuiceFactory { @Override public Juice createJuice() { return new OrangeJuice(); } } // Concrete Creator 2 class MangoJuiceFactory extends JuiceFactory { @Override public Juice createJuice() { return new MangoJuice(); } } // Client Code public class Main { public static void main(String[] args) { // Create an Orange Juice using its factory JuiceFactory orangeJuiceFactory = new OrangeJuiceFactory(); Juice orangeJuice = orangeJuiceFactory.createJuice(); orangeJuice.serve(); // Output: Serving Orange Juice. // Create a Mango Juice using its factory JuiceFactory mangoJuiceFactory = new MangoJuiceFactory(); Juice mangoJuice = mangoJuiceFactory.createJuice(); mangoJuice.serve(); // Output: Serving Mango Juice. } }
Modèles de conception structurelle
Ces modèles de conception se concentrent principalement sur la façon dont les classes et les objets sont composés pour former des structures plus grandes. Ils se concentrent sur l'organisation et les relations entre les objets et les classes, simplifiant la structure, améliorant la flexibilité et favorisant la maintenabilité.
- Modèle d'adaptateur : Dans ce modèle, nous permettons aux objets avec des interfaces incompatibles de fonctionner ensemble. Il agit comme un pont entre deux interfaces incompatibles, leur permettant de communiquer sans altérer leur code existant.
Clés essentielles du modèle d'adaptateur :
- Target Interface: It is an interface that will solve the problem (bridging the gap between the incompatible interfaces).
- Client: The class or code that interacts with the target interface.
- Adaptee: This is the interface which is not compatible with the current client requirements.
- Adapter: Implements the target interface and contains an instance of the adaptee. It translates requests from the target interface to the adaptee’s interface, making them compatible.
// Target Interface (Menu) interface Menu { void orderDish(String dish); } // Adaptee (Chef) class Chef { public void prepareDish(String dishName) { System.out.println("Chef is preparing " + dishName + "."); } } // Adapter (Waiter) class Waiter implements Menu { private Chef chef; public Waiter(Chef chef) { this.chef = chef; } @Override public void orderDish(String dish) { chef.prepareDish(dish); } } // Client Code public class Restaurant { public static void main(String[] args) { Chef chef = new Chef(); Menu waiter = new Waiter(chef); // Customer places an order via the waiter waiter.orderDish("Spaghetti Carbonara"); // Output: Chef is preparing Spaghetti Carbonara. } }
- Facade pattern: Simplifies the interaction with a complex system by providing a unified interface (facade). Instead of directly calling several different methods across various objects, the client interacts with the facade, which internally manages those operations.
Key essentials of the facade design pattern:
- Facade: It is an interface that wraps all the complex subsystem interfaces and delegates the complex tasks to the subsystems that actually perform the work.
- Subsystem Classes: These are the classes that acutally perform the work.
An example of facade design pattern:
The example illustrates the Facade Pattern which simplifies the process of washing, drying, and pressing clothes. It hides the complexity of interacting with multiple subsystems behind a single, unified interface.
// Subsystem Classes class WashingMachine { public void wash() { System.out.println("Washing clothes."); } } class Dryer { public void dry() { System.out.println("Drying clothes."); } } class Iron { public void press() { System.out.println("Pressing clothes."); } } // Facade Class class LaundryFacade { private WashingMachine washingMachine; private Dryer dryer; private Iron iron; public LaundryFacade(WashingMachine washingMachine, Dryer dryer, Iron iron) { this.washingMachine = washingMachine; this.dryer = dryer; this.iron = iron; } public void doLaundry() { System.out.println("Starting the laundry process..."); washingMachine.wash(); dryer.dry(); iron.press(); System.out.println("Laundry process complete."); } } // Client Code public class Main { public static void main(String[] args) { WashingMachine washingMachine = new WashingMachine(); Dryer dryer = new Dryer(); Iron iron = new Iron(); LaundryFacade laundryFacade = new LaundryFacade(washingMachine, dryer, iron); // Use the facade to do the laundry laundryFacade.doLaundry(); } }
Behavioral design patterns
The patterns that fall under this category mainly deals with communication between objects and how they interact with each other.
- Iterator pattern: In the Iterator Pattern, we define a way to sequentially access elements of a collection without needing to use conventional methods, such as for loops or direct indexing. Instead, the pattern provides a standard interface (usually methods like next() and hasNext()) to traverse the collection. This approach abstracts the iteration process, allowing the client to navigate through the collection without needing to understand its internal structure or use traditional iteration methods.
Key essentials of this pattern are:
- Iterator Interface: We define all the methods such as next(), hasNext(), and currentItem().These are used to traverse the collection.
- Concrete Iterator: This is the concrete implementation of the iterator interface.
- Aggregate Interface: In this interface,we define methods to create iterators.All the methods returns an instance of the Iterator.
- Concrete Aggregate: It's just a concrete implementation of the aggregate interface.
Example of iterator pattern:
This example demostrates a simple usecase of iterators a employees object using iterator pattern.
// Iterator Interface interface Iterator { boolean hasNext(); Object next(); } // Aggregate Interface interface Aggregate { Iterator createIterator(); } // Employee Class class Employee { public String Name; public int Age; public String Department; public int EmployeeId; public Employee(String name, int age, String department, int employeeId) { this.Name = name; this.Age = age; this.Department = department; this.EmployeeId = employeeId; } } // Concrete Aggregate class EmployeeCollection implements Aggregate { private Employee[] employees; public EmployeeCollection(Employee[] employees) { this.employees = employees; } @Override public Iterator createIterator() { return new EmployeeIterator(this.employees); } } // Concrete Iterator class EmployeeIterator implements Iterator { private Employee[] employees; private int position = 0; public EmployeeIterator(Employee[] employees) { this.employees = employees; } @Override public boolean hasNext() { return position
- Strategy pattern: In this pattern we define a family of algorithms, and at the runtime we choose the algorithm.Instead of implementing a single algorithm directly, the code receives runtime instructions on which algorithm to use from a family of algorithms. This pattern allows the algorithm to vary independently from the clients that use it.
Key essentials of this pattern are:
1.Strategy Interface: Defines the common interface for all supported algorithms.
2.Concrete Strategies: Implement the Strategy interface with specific algorithms.
3.Context: Uses a Strategy to execute the algorithm.
Example of strategy pattern:
Imagine we are building an encoding system where we may need to use different encoding algorithms depending on the situation. We will demonstrate this system using the Strategy Pattern.
// Strategy Interface interface EncoderStrategy { void encode(String string); } // Concrete Strategy for Base64 Encoding class Base64Encoder implements EncoderStrategy { @Override public void encode(String string) { // Implement Base64 encoding logic here System.out.println("This method uses Base64 encoding algorithm for: " + string); } } // Concrete Strategy for MD5 Encoding class MD5Encoder implements EncoderStrategy { @Override public void encode(String string) { // Implement MD5 encoding logic here System.out.println("This method uses MD5 encoding algorithm for: " + string); } } // Context Class class EncoderContext { private EncoderStrategy strategy; public void setEncoderMethod(EncoderStrategy strategy) { this.strategy = strategy; } public void encode(String string) { strategy.encode(string); } } // Usage public class Main { public static void main(String[] args) { EncoderContext context = new EncoderContext(); // Use Base64 encoding method context.setEncoderMethod(new Base64Encoder()); context.encode("A34937ifdsuhfweiur"); // Use MD5 encoding method context.setEncoderMethod(new MD5Encoder()); context.encode("89743297dfhksdhWOJO"); } }
Explanation:
- Firstly, we define the interface for the
- Next, we create concrete implementations of the interfaces that we have defined.
- Finally, we use these implementations to observe how a change in the subject also updates its dependents.
- Observer pattern: behavioral design pattern that establishes a one-to-many dependency between objects. This means that when one object (the subject) changes its state, all its dependent objects (observers) are notified and updated automatically. This pattern is particularly useful for implementing distributed event-handling systems in event-driven software.
Key essentials of this pattern are:
- Subject: It is an object which holds the state and informs the observers when it updates it's state.
- Observer: An interface or abstract class that defines the update method, which is called when the subject’s state changes.
- Concrete Subject: A class that implements the Subject interface and maintains the state of interest to observers.
- Concrete Observer: A class that implements the Observer interface and updates its state to match the subject’s state.
Example of observer pattern:
In a stock trading application, the stock ticker acts as the subject. Whenever the price of a stock is updated, various observers—such as investors and regulatory bodies—are notified of the change. This allows them to respond to price fluctuations in real-time.
import java.util.ArrayList; import java.util.List; // Observer interface interface Observer { void update(String stockSymbol, double stockPrice); } // Subject interface interface Subject { void register(Observer o); void remove(Observer o); void notify(); } // Concrete Subject class Stock implements Subject { private List<observer> observers; private String stockSymbol; private double stockPrice; public Stock() { observers = new ArrayList(); } public void setStock(String stockSymbol, double stockPrice) { this.stockSymbol = stockSymbol; this.stockPrice = stockPrice; notify(); } @Override public void register(Observer o) { observers.add(o); } @Override public void remove(Observer o) { observers.remove(o); } @Override public void notify() { for (Observer observer : observers) { observer.update(stockSymbol, stockPrice); } } } // Concrete Observer class StockTrader implements Observer { private String traderName; public StockTrader(String traderName) { this.traderName = traderName; } @Override public void update(String stockSymbol, double stockPrice) { System.out.println("Trader " + traderName + " notified. Stock: " + stockSymbol + " is now $" + stockPrice); } } // Usage public class Main { public static void main(String[] args) { Stock stock = new Stock(); StockTrader trader1 = new StockTrader("Niharika"); StockTrader trader2 = new StockTrader("Goulikar"); stock.register(trader1); stock.register(trader2); stock.setStock("Niha", 9500.00); stock.setStock("Rika", 2800.00); } } </observer>
Explanation:
- Firstly, we define the interface for the subject which is responsible for sending updates. Similarly, we also define an interface for the observer, which is responsible for receiving updates.
- Next, we create concrete implementations of the interfaces that we have defined.
- Finally, we use these implementations to observe how a change in the subject also updates its dependents.
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!

L'article discute de l'utilisation de Maven et Gradle pour la gestion de projet Java, la construction de l'automatisation et la résolution de dépendance, en comparant leurs approches et leurs stratégies d'optimisation.

L'article discute de la création et de l'utilisation de bibliothèques Java personnalisées (fichiers JAR) avec un versioning approprié et une gestion des dépendances, à l'aide d'outils comme Maven et Gradle.

L'article examine la mise en œuvre de la mise en cache à plusieurs niveaux en Java à l'aide de la caféine et du cache de goyave pour améliorer les performances de l'application. Il couvre les avantages de configuration, d'intégration et de performance, ainsi que la gestion de la politique de configuration et d'expulsion le meilleur PRA

L'article discute de l'utilisation de JPA pour la cartographie relationnelle des objets avec des fonctionnalités avancées comme la mise en cache et le chargement paresseux. Il couvre la configuration, la cartographie des entités et les meilleures pratiques pour optimiser les performances tout en mettant en évidence les pièges potentiels. [159 caractères]

Le chargement de classe de Java implique le chargement, la liaison et l'initialisation des classes à l'aide d'un système hiérarchique avec Bootstrap, Extension et Application Classloaders. Le modèle de délégation parent garantit que les classes de base sont chargées en premier, affectant la classe de classe personnalisée LOA


Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

VSCode Windows 64 bits Télécharger
Un éditeur IDE gratuit et puissant lancé par Microsoft

SublimeText3 Linux nouvelle version
Dernière version de SublimeText3 Linux

ZendStudio 13.5.1 Mac
Puissant environnement de développement intégré PHP

SublimeText3 version anglaise
Recommandé : version Win, prend en charge les invites de code !

Télécharger la version Mac de l'éditeur Atom
L'éditeur open source le plus populaire