Comment les programmeurs professionnels font-ils appel au jugement pour opter ou non pour la POO? Ce serait vraiment utile pour moi.
Pour moi, il y a deux points de décision. Tout d'abord, parfois, cela sera évident au début. Il y aura beaucoup de types similaires qui partagent tous des méthodes communes qui diffèrent considérablement dans leurs détails d'implémentation. Par exemple, je construisais un système de workflow et j'avais besoin de pouvoir implémenter des tâches arbitraires. Pour exécuter la tâche, j'ai implémenté une classe de base dont chaque tâche a hérité, avec une Execute()
méthode abstraite. Les classes héritées fournissaient l'implémentation, mais le système de workflow pouvait commencer l'exécution sans rien savoir du type de tâche en cours d'exécution.
Cependant, la plupart des projets ne sont pas aussi clairs. Le deuxième point de décision est lorsqu'un sous-ensemble du projet est devenu un énorme enchevêtrement d'instructions if-then ou d'instructions switch-case, et surtout lorsque ces instructions if-then nécessitent beaucoup de code de configuration pour fonctionner correctement. Je me sens commencer à perdre la logique de ce que j'essaie d'accomplir, et le code commence à se sentir fragile. À ce stade, c'est généralement un signe qu'il est temps de refactoriser le code en classes de base avec des implémentations spécifiques.
Une grande partie du passage à un style orienté objet par opposition à un style fonctionnel consiste à convertir les instructions if-then en instructions "exécuter cette action". Au lieu d'un énorme ensemble d'instructions if-then, vous dites simplement au code d'exécuter son action. L'action réellement exécutée dépend de l'implémentation que vous avez fournie.
Par exemple, voici le style fonctionnel du pseudocode de style C #:
if ( action == "email" ) {
callEmailFunction(userInfo);
}
else if ( action == "sms" ) {
callSmsFunction(userInfo);
}
else if ( action == "web" ) {
endpoint = "http://127.0.0.1/confirm";
confirmWeb(endpoint, userinfo);
}
...
Mais peut-être pourriez-vous réécrire cela à quelque chose comme ceci:
interface IConfirmable {
void Confirm(UserInfo userinfo);
}
public class ConfirmEmail : IConfirmable {
public void Confirm(UserInfo userinfo) {
// do the appropriate thing to confirm via email
}
}
public class ConfirmSms : IConfirmable {
public void Confirm(UserInfo userinfo) {
// do the appropriate thing to confirm via email
}
}
public class ConfirmWeb : IConfirmable {
// this is a constructor
public ConfirmWeb(string endpoint) {
...
}
public void Confirm(UserInfo userinfo) {
// do the appropriate thing to confirm via web
}
}
Et puis le code lui-même:
// An implementation that decides which implementation of the base class to use
// This replaces the if-then statements in the functional programmming.
IConfirmable confirmer = ConfirmerFactory.GetConfirmer();
// get the userinfo however you get it,
// which would be the same way you get it in the functional example.
UserInfo userinfo = ...;
// perform the action.
confirmer.Confirm(userinfo);
Maintenant, quand il y a très peu de code à l'intérieur du if-then, cela ressemble à beaucoup de travail pour n'en tirer aucun avantage. Et quand il y a très peu de code dans le si-alors, c'est correct: c'est beaucoup de travail pour le code qui est plus difficile à comprendre.
Mais le style orienté objet brille vraiment lorsque vous avez plus d'une action que la Confirm()
méthode qui doit être exécutée. Vous disposez peut-être d'une routine d'initialisation, de trois méthodes d'action ou plus pouvant être exécutées et d'une Cleanup()
méthode. L'algorithme de base est identique, sauf qu'il effectue ses appels dans les objets appropriés qui implémentent une classe de base commune. Maintenant, vous commencez à voir un réel avantage pour le style orienté objet: l'algorithme de base est beaucoup plus facile à lire que s'il vérifiait les instructions if-then à chaque étape du processus.