4 votes

Pont de la méthode orientée objet

Plusieurs ressources de mon système utilisent le concept de collections d'objets, basé sur les collections de Java.

Cette classe de collection (abstraite) fournit des fonctionnalités de base à une autre classe concrète, appelée Listes, qui permet de trouver des objets grâce aux index de la collection.

J'utiliserai comme exemple ma classe d'en-têtes HTTP pour expliquer.

J'ai, dans son constructeur, une instance de cette classe de listes. Chaque champ d'en-tête HTTP est ajouté à la collection par l'intermédiaire de En-têtes::addHeader() método.

Évidemment, j'ai une getter méthode appelée getHeaders() qui renvoient les Stockage et non celui de la Collection Objet .

Ainsi, si j'ai besoin de lister les en-têtes en dehors de cette classe, il me suffit d'appeler $obj -> getHeaders() et j'ai un ArrayObject avec tous les objets ajoutés.

D'accord !

Mais, récemment, est apparue la nécessité d'utiliser l'une des méthodes de Lists, Listes::find() qui trouve un objet sans même connaître le nom de l'objet ou sa position spécifique dans le stockage de la collection.

Puisque l'objet Lists est dans une propriété privée, Headers::getHeaders() renvoie le Collection Storage et je ne veux pas violer l'encapsulation, en rendant la propriété publique, je ne peux pas accéder à cette méthode.

Tout ce que je code, en plus de la fonctionnalité, doit être visuellement élégant, et créer une autre méthode getter, disons getHeadersLists() produirait une invocation comme :

$obj -> getHeadersLists() -> find( 'foo' );

C'est moche !

J'ai donc rapidement ajouté un __call() dans la classe Headers et cela a bien fonctionné :

$obj -> find( 'foo' );

Mais quelqu'un que je connais (et qui est très versé dans le thème de l'orientation objet) m'a dit que c'était faux.

Mon argument était purement axé sur la lisibilité, et il a rétorqué que "dans l'orientation objet, les méthodes magiques et la lisibilité ne peuvent pas coexister".

Et alors ? Que dois-je faire pour créer ce "pont" entre ces deux classes, sans utiliser de _call() et en préservant les principes de l'Orientation Objet ?

Je sais que je pourrais retourner l'objet Collection dans Headers::getHeaders() et utiliser quelque chose comme :

$obj -> getHeaders() -> find();

Mais ce que j'ai appris sur l'orientation objet, c'est la responsabilité. La responsabilité de cette méthode, comme l'indique sa déclaration, est de renvoyer tous les en-têtes ajoutés et non un objet extérieur.

1voto

Ali Akdurak Points 734

J'ai l'intention de vous présenter le principe de responsabilité unique de l'oncle Bob (le grand S de S.O.L.I.D.). Pour en savoir plus, consultez le site Principes de l'OOD article. Et pour répondre directement à votre question Très bel article et exemple de Tom Dalling .

Single Responsibility Principle. Acknowledgement I have no rights or claims on this image.

Le problème se pose lorsque vous cachez l'appel à la fonction getHeaders() qui renvoie un objet de type Listes alors il semble que vous appelez l'objet et qu'il a une fonction appelée find "qu'il ne devrait pas avoir" car ce n'est pas sa responsabilité de trouver des en-têtes corrects.

Je comprends votre approche de la responsabilité.

Vous dites : Lorsque j'appelle getHeaders(), je ne devrais pas être obligé de manipuler davantage le résultat pour obtenir ce que je veux.

Votre suggestion est tout à fait correct . Mais pour obtenir ce résultat, il faut cacher l'appel à la fonction getHeaders() avec le sucre syntaxique suivant complètement faux Parce qu'il va m'induire en erreur.

Si je lis votre code en tant que tiers, je supposerai immédiatement qu'il existe une fonction find() de cette classe, ce qui est très trompeur. Je rejetterais également cette fonction find() car la recherche dans une liste d'en-têtes n'est pas une responsabilité attendue de l'objet, ce n'est qu'un ajout inutile ou une erreur. Votre collègue a donc raison :D.

Je crois que les circonstances vous obligent à appeler trouver() pour pouvoir utiliser le En-têtes L'objet type est à blâmer dans ce cas.

Ma suggestion pour résoudre votre dilemme est la suivante.

  1. Cet objet devrait très certainement avoir une fonction appelée getHeaders(). Ne la changez pas. Elle doit retourner tous les en-têtes.
  2. Créez une deuxième fonction appelée getRelatedHeaders("foo") ou getFooHeaders() qui appelle getHeaders() à l'intérieur d'une manière encapsulée, puis utilise find("foo") sur eux et renvoie vos en-têtes "foo".

Il ne reste plus qu'une petite suggestion à faire à mon ami. Je pense que votre discussion suscite une question bien plus intéressante que vous et votre coéquipier devriez poser.

Presque toujours, si vous avez besoin d'obtenir certaines propriétés d'un objet et d'agir sur elles. Vous devez également être en mesure d'encapsuler cette fonctionnalité dans cet objet/classe. C'est presque toujours une odeur de code lorsque vous récupérez une propriété d'un objet et que vous l'utilisez pour faire quelque chose, puis que vous la remettez à sa place.

W manipule ses propriétés à sa place ?

Merci pour votre temps, j'espère que je vous ai aidé d'une manière ou d'une autre :D.

0voto

umlcat Points 2025

C'est pourquoi il existe un champ d'application "protégé", en PHP, comme dans les autres langages de programmation de l'O.O..

Au cas où vous le sauriez, un membre "protégé" peut être accédé par les classes descendantes, mais ne peut pas être accédé en tant que membre public.

En guise de suggestion, je n'utilise généralement pas le terme "privé", mais plutôt le terme "protégé", pour les mêmes raisons que celles évoquées dans votre message.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X