Disons que pour une raison quelconque, tous les objets sont créés de cette façon $ obj = CLASS :: getInstance (). Ensuite, nous injectons des dépendances à l'aide de setters et effectuons le démarrage de l'initialisation à l'aide de $ obj-> initInstance (); Y a-t-il de vrais problèmes ou situations qui ne peuvent pas être résolus si nous n'utilisons pas du tout de constructeurs?
Ps la raison de créer un objet de cette façon, c'est que nous pouvons remplacer la classe à l'intérieur de getInstance () selon certaines règles.
Je travaille en PHP, si c'est important
object-oriented-design
class-design
Axel Foley
la source
la source
Réponses:
Je dirais que cela entrave considérablement votre espace de conception.
Les constructeurs sont un excellent endroit pour initialiser et valider les paramètres transmis. Si vous ne pouvez plus les utiliser pour cela, alors l'initialisation, la gestion des états (ou tout simplement le refus du constructeur d'objets "cassés") devient beaucoup plus difficile et partiellement impossible.
Par exemple, si chaque
Foo
objet a besoin d'un,Frobnicator
il peut archiver son constructeur si leFrobnicator
n'est pas nul. Si vous enlevez le constructeur, il devient plus difficile à vérifier. Vérifiez-vous à chaque point où il serait utilisé? Dans uneinit()
méthode (externaliser efficacement la méthode constructeur)? Ne le vérifiez jamais et espérez le meilleur?Bien que vous puissiez probablement tout mettre en œuvre (après tout, vous êtes toujours en train de terminer), certaines choses seront beaucoup plus difficiles à faire.
Personnellement, je suggérerais d'examiner l' injection de dépendance / l' inversion du contrôle . Ces techniques permettent également de changer de classe d'implémentation concrète, mais elles n'empêchent pas l'écriture / l'utilisation de constructeurs.
la source
HttpClient
il vérifie si ce paramètre n'est pas nul). Et si ces contraintes ne sont pas respectées, il peut alors lever une exception. Ce n'est pas vraiment possible avec l'approche des valeurs de construction et de définition.init()
, ce qui est tout à fait possible, bien que cela impose simplement une charge de maintenance plus importante.2 avantages pour les constructeurs:
Les constructeurs permettent d'effectuer les étapes de construction d'un objet de manière atomique.
Je pourrais éviter un constructeur et utiliser des setters pour tout, mais qu'en est-il des propriétés obligatoires comme l'a suggéré Joachim Sauer? Avec un constructeur, un objet possède sa propre logique de construction afin de s'assurer qu'il n'y a pas d'instances invalides d'une telle classe .
Si la création d'une instance de
Foo
requiert la définition de 3 propriétés, le constructeur peut prendre une référence aux 3, les valider et lever une exception si elles ne sont pas valides.Encapsulation
En s'appuyant uniquement sur les poseurs, la charge incombe au consommateur d'un objet de le construire correctement. Il peut exister différentes combinaisons de propriétés valides.
Par exemple, chaque
Foo
instance a besoin d'une instance deBar
as propertybar
ou d'une instance deBarFinder
as propertybarFinder
. Il peut utiliser l'un ou l'autre. Vous pouvez créer un constructeur pour chaque ensemble valide de paramètres et appliquer les conventions de cette façon.La logique et la sémantique des objets vivent dans l'objet lui-même. C'est une bonne encapsulation.
la source
Oui, vous pouvez vivre sans constructeurs.
Bien sûr, vous pouvez vous retrouver avec beaucoup de code de plaque de chaudière dupliqué. Et si votre application est de n'importe quelle échelle, vous passerez probablement beaucoup de temps à essayer de localiser la source d'un problème lorsque ce code passe-partout n'est pas utilisé de manière cohérente dans l'application.
Mais non, vous n'avez pas strictement besoin de vos propres constructeurs. Bien sûr, vous n'avez pas non plus strictement besoin de classes et d'objets.
Maintenant, si votre objectif est d'utiliser une sorte de modèle d'usine pour la création d'objets, cela ne s'exclut pas mutuellement d'utiliser des constructeurs lors de l'initialisation de vos objets.
la source
L'avantage d'utiliser des constructeurs est qu'ils permettent de garantir plus facilement que vous n'aurez jamais d'objet invalide.
Un constructeur vous donne la possibilité de définir toutes les variables membres de l'objet dans un état valide. Lorsque vous vous assurez qu'aucune méthode de mutation ne peut changer l'objet en un état non valide, vous n'aurez jamais d'objet non valide, ce qui vous évitera de nombreux bogues.
Mais lorsqu'un nouvel objet est créé dans un état non valide et que vous devez appeler certains setters pour le mettre dans un état valide dans lequel il peut être utilisé, vous risquez qu'un consommateur de la classe oublie d'appeler ces setters ou les appelle incorrectement et vous vous retrouvez avec un objet invalide.
Une solution de contournement pourrait être de créer des objets uniquement via une méthode d'usine qui vérifie la validité de chaque objet qu'il crée avant de le renvoyer à l'appelant.
la source
Je pense que vous rendez cela plus difficile que nécessaire. Nous pouvons très bien injecter des dépendances via le constructeur - et si vous en avez beaucoup, utilisez simplement une structure de type dictionnaire pour pouvoir spécifier celles que vous souhaitez utiliser:
Et au sein du constructeur, vous pouvez assurer la cohérence comme suit:
$args
peut ensuite être utilisé pour définir des membres privés si nécessaire.Une fois fait entièrement dans le constructeur comme tel, il n'y aura jamais un état intermédiaire où il
$obj
existe mais n'est pas initialisé, comme ce serait le cas dans le système décrit dans la question. Il vaut mieux éviter de tels états intermédiaires, car vous ne pouvez pas garantir que l'objet sera toujours utilisé correctement.la source
Je pensais en fait à des choses similaires.
La question que j'ai posée était "Quel constructeur fait, et est-il possible de le faire différemment?" Je suis arrivé à ces conclusions:
Il garantit que certaines propriétés sont initialisées. En les acceptant comme paramètres et en les définissant. Mais cela pourrait facilement être appliqué par le compilateur. En annotant simplement les champs ou les propriétés comme "requis", le compilateur vérifierait lors de la création de l'instance si tout est correctement défini. L'appel à créer l'instance serait probablement le même, il n'y aurait tout simplement pas de méthode constructeur.
Garantit que les propriétés sont valides. Cela pourrait être facilement réalisé par l'affirmation de la condition. Encore une fois, vous annoteriez simplement les propriétés avec des conditions correctes. Certaines langues le font déjà.
Une logique de construction plus complexe. Les modèles modernes ne recommandent pas de le faire dans le constructeur, mais proposent d'utiliser des méthodes ou des classes d'usine spécialisées. Ainsi, l'utilisation de constructeurs dans ce cas est minime.
Donc pour répondre à votre question: oui, je crois que c'est possible. Mais cela nécessiterait de grands changements dans la conception du langage.
Et je viens de remarquer que ma réponse est plutôt OT.
la source
Oui, vous pouvez presque tout faire sans utiliser de constructeurs, mais cela gaspille clairement les avantages des langages de programmation orientée objet.
Dans les langages modernes (je parlerai ici de C # dans lequel je programme), vous pouvez limiter les parties de code qui ne peuvent être exécutées que dans un constructeur. Grâce à laquelle vous pouvez éviter les erreurs maladroites. L'une de ces choses est le modificateur en lecture seule :
Comme recommandé par Joachim Sauer précédemment au lieu d'utiliser le
Factory
design design, lisez la suiteDependency Injection
. Je recommanderais la lecture de l' injection de dépendance dans .NET par Mark Seemann .la source
Instancier un objet avec un type en fonction des besoins c'est absolument possible. Il peut s'agir de l'objet lui-même, utilisant des variables globales du système pour renvoyer un type spécifique.
Cependant, avoir une classe dans le code qui peut être "All" est le concept de type dynamique . Personnellement, je crois que cette approche crée une incohérence dans votre code, rend les complexes de test * et "l'avenir devient incertain" en ce qui concerne le flux du travail proposé.
* Je fais référence au fait que les tests doivent considérer d'abord le type, ensuite le résultat que vous souhaitez obtenir. Ensuite, vous créez un grand test imbriqué.
la source
Pour équilibrer certaines des autres réponses, en affirmant:
et
De telles déclarations impliquent parfois l'hypothèse que:
Mais ce n'est pas tout à fait vrai. La plupart des langages n'ont pas de règle interdisant à un constructeur de passer
this
(self
ou quel que soit le langage qu'il appelle) à du code externe. Un tel constructeur respecte complètement la règle énoncée ci-dessus, et pourtant il risque d'exposer des objets semi-construits à du code externe. C'est un point mineur mais facilement ignoré.la source
C'est quelque peu anecdotique, mais je réserve généralement des constructeurs à l'état essentiel pour que l'objet soit complet et utilisable. Sauf injection de setter, une fois le constructeur exécuté, mon objet devrait pouvoir effectuer les tâches qui lui sont demandées.
Tout ce qui peut être différé, je laisse de côté le constructeur (préparation des valeurs de sortie, etc.). Avec cette approche, je pense ne pas utiliser de constructeurs pour quoi que ce soit, mais l'injection de dépendances a du sens.
Cela a également l'avantage supplémentaire de câbler durement votre processus de conception mentale pour ne rien faire prématurément. Vous n'initialiserez pas ou n'effectuerez pas de logique qui pourrait ne jamais être utilisée, car au mieux tout ce que vous faites est une configuration de base pour le travail à venir.
la source