Principe ouvert / fermé en Java

1. Vue d'ensemble

Dans ce didacticiel, nous aborderons le principe ouvert / fermé (OCP) comme l'un des principes SOLID de la programmation orientée objet.

Dans l'ensemble, nous détaillerons ce qu'est ce principe et comment le mettre en œuvre lors de la conception de notre logiciel.

2. Principe ouvert / fermé

Comme son nom l'indique, ce principe stipule que les entités logicielles doivent être ouvertes à l'extension, mais fermées pour modification. En conséquence, lorsque les exigences commerciales changent, l'entité peut être étendue, mais pas modifiée.

Pour l'illustration ci-dessous, nous allons nous concentrer sur la façon dont les interfaces sont un moyen de suivre OCP.

2.1. Non conforme

Considérons que nous construisons une application de calcul qui pourrait avoir plusieurs opérations, telles que l'addition et la soustraction.

Tout d'abord, nous allons définir une interface de premier niveau - CalculatorOperation :

public interface CalculatorOperation {}

Définissons une classe Addition , qui ajouterait deux nombres et implémenterait le C alculatorOperation :

public class Addition implements CalculatorOperation { private double left; private double right; private double result = 0.0; public Addition(double left, double right) { this.left = left; this.right = right; } // getters and setters }

Pour le moment, nous n'avons qu'une seule classe Addition, nous devons donc définir une autre classe nommée Soustraction :

public class Subtraction implements CalculatorOperation { private double left; private double right; private double result = 0.0; public Subtraction(double left, double right) { this.left = left; this.right = right; } // getters and setters }

Définissons maintenant notre classe principale, qui effectuera nos opérations de calculatrice:

public class Calculator { public void calculate(CalculatorOperation operation) { if (operation == null) { throw new InvalidParameterException("Can not perform operation"); } if (operation instanceof Addition) { Addition addition = (Addition) operation; addition.setResult(addition.getLeft() + addition.getRight()); } else if (operation instanceof Subtraction) { Subtraction subtraction = (Subtraction) operation; subtraction.setResult(subtraction.getLeft() - subtraction.getRight()); } } }

Bien que cela puisse sembler correct, ce n'est pas un bon exemple de l'OCP. Quand une nouvelle exigence d'ajouter la multiplication ou la fonctionnalité de partage entre, nous avons aucun moyen en plus de changer la calculate méthode de la calculatrice classe.

Par conséquent, nous pouvons dire que ce code n'est pas conforme à OCP.

2.2. Conforme OCP

Comme nous l'avons vu, notre application de calcul n'est pas encore conforme à OCP. Le code de la méthode de calcul changera à chaque nouvelle demande de support d'opération entrante. Nous devons donc extraire ce code et le placer dans une couche d'abstraction.

Une solution consiste à déléguer chaque opération dans leur classe respective:

public interface CalculatorOperation { void perform(); }

En conséquence, la classe Addition pourrait implémenter la logique de l'ajout de deux nombres:

public class Addition implements CalculatorOperation { private double left; private double right; private double result; // constructor, getters and setters @Override public void perform() { result = left + right; } }

De même, une classe de soustraction mise à jour aurait une logique similaire. Et comme pour Addition et Soustraction , en tant que nouvelle demande de changement, nous pourrions implémenter la logique de division :

public class Division implements CalculatorOperation { private double left; private double right; private double result; // constructor, getters and setters @Override public void perform() { if (right != 0) { result = left / right; } } }

Et enfin, notre classe Calculator n'a pas besoin d'implémenter une nouvelle logique lorsque nous introduisons de nouveaux opérateurs:

public class Calculator { public void calculate(CalculatorOperation operation) { if (operation == null) { throw new InvalidParameterException("Cannot perform operation"); } operation.perform(); } } 

De cette façon, la classe est fermée pour modification mais ouverte pour une extension.

3. Conclusion

Dans ce tutoriel, nous avons appris ce qu'est OCP par définition, puis nous avons développé cette définition. Nous avons ensuite vu un exemple d'application de calculatrice simple dont la conception était défectueuse. Enfin, nous avons amélioré le design en le faisant adhérer à l'OCP.

Comme toujours, le code est disponible sur sur GitHub.