Συχνές ερωτήσεις σχετικά με το DI (FAQ)

Είναι το DI ένα άλλο όνομα για το IoC;

Η Inversion of Control (IoC) είναι μια αρχή που επικεντρώνεται στον τρόπο εκτέλεσης του κώδικα – αν ο κώδικάς σας εκκινεί εξωτερικό κώδικα ή αν ο κώδικάς σας ενσωματώνεται σε εξωτερικό κώδικα, ο οποίος στη συνέχεια τον καλεί. Η IoC είναι μια ευρεία έννοια που περιλαμβάνει γεγονότα, τη λεγόμενη αρχή του Χόλιγουντ και άλλες πτυχές. Τα εργοστάσια, τα οποία αποτελούν μέρος του κανόνα #3: Let the Factory Handle It, και αντιπροσωπεύουν την αντιστροφή για τον τελεστή new, είναι επίσης συστατικά αυτής της έννοιας.

Το Dependency Injection (DI) αφορά το πώς ένα αντικείμενο γνωρίζει για ένα άλλο αντικείμενο, δηλαδή την εξάρτηση. Πρόκειται για ένα πρότυπο σχεδίασης που απαιτεί ρητή μεταβίβαση εξαρτήσεων μεταξύ αντικειμένων.

Έτσι, το DI μπορεί να ειπωθεί ότι είναι μια ειδική μορφή του IoC. Ωστόσο, δεν είναι όλες οι μορφές IoC κατάλληλες όσον αφορά την καθαρότητα του κώδικα. Για παράδειγμα, στα αντι-πρότυπα περιλαμβάνουμε όλες τις τεχνικές που λειτουργούν με την παγκόσμια κατάσταση ή το λεγόμενο Service Locator.

Τι είναι ο εντοπιστής υπηρεσιών;

Ο εντοπιστής υπηρεσιών είναι μια εναλλακτική λύση για την ένθεση εξαρτήσεων (Dependency Injection). Λειτουργεί με τη δημιουργία ενός κεντρικού αποθηκευτικού χώρου όπου καταχωρούνται όλες οι διαθέσιμες υπηρεσίες ή εξαρτήσεις. Όταν ένα αντικείμενο χρειάζεται μια εξάρτηση, τη ζητάει από το Service Locator.

Ωστόσο, σε σύγκριση με το Dependency Injection, χάνει σε διαφάνεια: οι εξαρτήσεις δεν μεταβιβάζονται απευθείας σε αντικείμενα και επομένως δεν είναι εύκολα αναγνωρίσιμες, γεγονός που απαιτεί την εξέταση του κώδικα για να αποκαλυφθούν και να κατανοηθούν όλες οι συνδέσεις. Η δοκιμή είναι επίσης πιο περίπλοκη, καθώς δεν μπορούμε απλά να περάσουμε αντικείμενα προσομοίωσης στα δοκιμαζόμενα αντικείμενα, αλλά πρέπει να περάσουμε μέσω του Service Locator. Επιπλέον, ο Service Locator διαταράσσει τη σχεδίαση του κώδικα, καθώς τα μεμονωμένα αντικείμενα πρέπει να γνωρίζουν την ύπαρξή του, κάτι που διαφέρει από το Dependency Injection, όπου τα αντικείμενα δεν έχουν καμία γνώση του DI container.

Πότε είναι καλύτερο να μην χρησιμοποιείται το DI;

Δεν υπάρχουν γνωστές δυσκολίες που σχετίζονται με τη χρήση του προτύπου σχεδίασης Dependency Injection. Αντιθέτως, η απόκτηση εξαρτήσεων από παγκοσμίως προσβάσιμες θέσεις οδηγεί σε αρκετές επιπλοκές, όπως και η χρήση ενός Service Locator. Επομένως, είναι σκόπιμο να χρησιμοποιείτε πάντα το DI. Αυτή δεν είναι μια δογματική προσέγγιση, αλλά απλά δεν έχει βρεθεί καλύτερη εναλλακτική λύση.

Ωστόσο, υπάρχουν ορισμένες καταστάσεις όπου δεν περνάμε αντικείμενα μεταξύ μας και τα λαμβάνουμε από τον παγκόσμιο χώρο. Για παράδειγμα, όταν κάνουμε αποσφαλμάτωση κώδικα και χρειάζεται να απορρίψουμε την τιμή μιας μεταβλητής σε ένα συγκεκριμένο σημείο του προγράμματος, να μετρήσουμε τη διάρκεια ενός συγκεκριμένου τμήματος του προγράμματος ή να καταγράψουμε ένα μήνυμα. Σε τέτοιες περιπτώσεις, όπου πρόκειται για προσωρινές ενέργειες που θα αφαιρεθούν αργότερα από τον κώδικα, είναι θεμιτό να χρησιμοποιείται ένας dumper, ένα χρονόμετρο ή ένας καταγραφέας με παγκόσμια πρόσβαση. Αυτά τα εργαλεία, άλλωστε, δεν ανήκουν στον σχεδιασμό του κώδικα.

Η χρήση DI έχει τα μειονεκτήματά της;

Η χρήση του Dependency Injection συνεπάγεται μειονεκτήματα, όπως αυξημένη πολυπλοκότητα στη συγγραφή κώδικα ή χειρότερες επιδόσεις; Τι χάνουμε όταν αρχίζουμε να γράφουμε κώδικα σύμφωνα με το DI;

Η DI δεν έχει καμία επίπτωση στην απόδοση της εφαρμογής ή στις απαιτήσεις μνήμης. Η απόδοση του DI Container μπορεί να παίζει κάποιο ρόλο, αλλά στην περίπτωση του Nette DI, το container μεταγλωττίζεται σε καθαρή PHP, οπότε η επιβάρυνσή του κατά την εκτέλεση της εφαρμογής είναι ουσιαστικά μηδενική.

Κατά τη συγγραφή κώδικα, είναι απαραίτητο να δημιουργηθούν κατασκευαστές που δέχονται εξαρτήσεις. Στο παρελθόν, αυτό μπορούσε να είναι χρονοβόρο, αλλά χάρη στα σύγχρονα IDE και την προώθηση ιδιοτήτων των κατασκευαστών, είναι πλέον θέμα λίγων δευτερολέπτων. Οι κατασκευαστές μπορούν εύκολα να δημιουργηθούν χρησιμοποιώντας το Nette DI και ένα πρόσθετο PhpStorm με λίγα μόνο κλικ. Από την άλλη πλευρά, δεν χρειάζεται να γράψετε singletons και στατικά σημεία πρόσβασης.

Μπορούμε να συμπεράνουμε ότι μια σωστά σχεδιασμένη εφαρμογή που χρησιμοποιεί DI δεν είναι ούτε μικρότερη ούτε μεγαλύτερη σε σύγκριση με μια εφαρμογή που χρησιμοποιεί singletons. Τμήματα του κώδικα που εργάζονται με εξαρτήσεις απλώς εξάγονται από μεμονωμένες κλάσεις και μεταφέρονται σε νέες θέσεις, δηλαδή στον περιέκτη DI και στα εργοστάσια.

Πώς να ξαναγράψετε μια παλαιά εφαρμογή σε DI;

Η μετάβαση από μια παλαιά εφαρμογή σε Dependency Injection μπορεί να είναι μια δύσκολη διαδικασία, ειδικά για μεγάλες και πολύπλοκες εφαρμογές. Είναι σημαντικό να προσεγγίσετε αυτή τη διαδικασία συστηματικά.

  • Κατά τη μετάβαση σε Dependency Injection, είναι σημαντικό όλα τα μέλη της ομάδας να κατανοήσουν τις αρχές και τις πρακτικές που χρησιμοποιούνται.
  • Αρχικά, πραγματοποιήστε μια ανάλυση της υπάρχουσας εφαρμογής για να εντοπίσετε τα βασικά στοιχεία και τις εξαρτήσεις τους. Δημιουργήστε ένα σχέδιο για το ποια μέρη θα αναδιαμορφωθούν και με ποια σειρά.
  • Υλοποιήστε έναν περιέκτη DI ή, ακόμα καλύτερα, χρησιμοποιήστε μια υπάρχουσα βιβλιοθήκη όπως η Nette DI.
  • Αναδιαμορφώστε σταδιακά κάθε τμήμα της εφαρμογής ώστε να χρησιμοποιεί Dependency Injection. Αυτό μπορεί να περιλαμβάνει την τροποποίηση κατασκευαστών ή μεθόδων ώστε να δέχονται εξαρτήσεις ως παραμέτρους.
  • Τροποποιήστε τα σημεία του κώδικα όπου δημιουργούνται αντικείμενα εξάρτησης έτσι ώστε οι εξαρτήσεις να εγχέονται από τον περιέκτη. Αυτό μπορεί να περιλαμβάνει τη χρήση εργοστασίων.

Να θυμάστε ότι η μετάβαση σε Dependency Injection είναι μια επένδυση στην ποιότητα του κώδικα και στη μακροπρόθεσμη βιωσιμότητα της εφαρμογής. Αν και μπορεί να είναι πρόκληση να γίνουν αυτές οι αλλαγές, το αποτέλεσμα θα πρέπει να είναι καθαρότερος, πιο αρθρωτός και εύκολα ελέγξιμος κώδικας που είναι έτοιμος για μελλοντικές επεκτάσεις και συντήρηση.

Γιατί η σύνθεση προτιμάται από την κληρονομικότητα;

Είναι προτιμότερο να χρησιμοποιείται η σύνθεση αντί για την κληρονομικότητα, επειδή χρησιμεύει στην επαναχρησιμοποίηση του κώδικα χωρίς να χρειάζεται να ανησυχείτε για τις συνέπειες των αλλαγών. Έτσι, παρέχει μια πιο χαλαρή σύζευξη, όπου δεν χρειάζεται να ανησυχούμε ότι η αλλαγή κάποιου κώδικα θα προκαλέσει την ανάγκη αλλαγής άλλου εξαρτημένου κώδικα. Ένα τυπικό παράδειγμα είναι μια κατάσταση που αναφέρεται ως κόλαση των κατασκευαστών.

Μπορεί το Nette DI Container να χρησιμοποιηθεί εκτός της Nette;

Απολύτως. Το Nette DI Container είναι μέρος του Nette, αλλά έχει σχεδιαστεί ως αυτόνομη βιβλιοθήκη που μπορεί να χρησιμοποιηθεί ανεξάρτητα από άλλα μέρη του πλαισίου. Απλά εγκαταστήστε το χρησιμοποιώντας το Composer, δημιουργήστε ένα αρχείο ρυθμίσεων που ορίζει τις υπηρεσίες σας και στη συνέχεια χρησιμοποιήστε μερικές γραμμές κώδικα PHP για να δημιουργήσετε το DI container. Και μπορείτε αμέσως να αρχίσετε να εκμεταλλεύεστε το Dependency Injection στα έργα σας.

Το κεφάλαιο Nette DI Container περιγράφει πώς μοιάζει μια συγκεκριμένη περίπτωση χρήσης, συμπεριλαμβανομένου του κώδικα.

Γιατί η διαμόρφωση βρίσκεται σε αρχεία NEON;

Το NEON είναι μια απλή και ευανάγνωστη γλώσσα ρυθμίσεων που αναπτύχθηκε στο πλαίσιο της Nette για τη ρύθμιση εφαρμογών, υπηρεσιών και των εξαρτήσεών τους. Σε σύγκριση με το JSON ή το YAML, προσφέρει πολύ πιο διαισθητικές και ευέλικτες επιλογές για το σκοπό αυτό. Στη NEON, μπορείτε φυσικά να περιγράψετε δεσμεύσεις που δεν θα ήταν δυνατόν να γραφτούν σε Symfony & YAML είτε καθόλου είτε μόνο μέσω μιας πολύπλοκης περιγραφής.

Επιβραδύνει η ανάλυση των αρχείων NEON την εφαρμογή;

Παρόλο που τα αρχεία NEON αναλύονται πολύ γρήγορα, αυτή η πτυχή δεν έχει πραγματικά σημασία. Ο λόγος είναι ότι η ανάλυση των αρχείων γίνεται μόνο μία φορά κατά την πρώτη εκκίνηση της εφαρμογής. Μετά από αυτό, ο κώδικας δοχείου DI δημιουργείται, αποθηκεύεται στο δίσκο και εκτελείται για κάθε επόμενη αίτηση χωρίς να χρειάζεται περαιτέρω ανάλυση.

Έτσι λειτουργεί σε ένα περιβάλλον παραγωγής. Κατά τη διάρκεια της ανάπτυξης, τα αρχεία NEON αναλύονται κάθε φορά που αλλάζει το περιεχόμενό τους, διασφαλίζοντας ότι ο προγραμματιστής έχει πάντα ένα ενημερωμένο DI container. Όπως αναφέρθηκε προηγουμένως, η πραγματική ανάλυση είναι θέμα μιας στιγμής.

Πώς μπορώ να προσπελάσω τις παραμέτρους από το αρχείο διαμόρφωσης στην κλάση μου;

Λάβετε υπόψη σας τον Κανόνας #1: Αφήστε να περάσει σε σας. Εάν μια κλάση απαιτεί πληροφορίες από ένα αρχείο ρυθμίσεων, δεν χρειάζεται να βρούμε πώς να αποκτήσουμε πρόσβαση σε αυτές τις πληροφορίες- αντίθετα, απλά τις ζητάμε – για παράδειγμα, μέσω του κατασκευαστή της κλάσης. Και εκτελούμε την πάσα στο αρχείο διαμόρφωσης.

Σε αυτό το παράδειγμα, το %myParameter% είναι ένας χώρος τοποθέτησης για την τιμή της παραμέτρου myParameter, η οποία θα μεταβιβαστεί στον κατασκευαστή MyClass:

# config.neon
parameters:
	myParameter: Some value

services:
	- MyClass(%myParameter%)

Εάν θέλετε να περάσετε πολλαπλές παραμέτρους ή να χρησιμοποιήσετε αυτόματη σύνδεση, είναι χρήσιμο να τυλίξετε τις παραμέτρους σε ένα αντικείμενο.

Υποστηρίζει η Nette τη διεπαφή PSR-11 Container;

Το Nette DI Container δεν υποστηρίζει άμεσα το PSR-11. Ωστόσο, αν χρειάζεστε διαλειτουργικότητα μεταξύ του Nette DI Container και βιβλιοθηκών ή πλαισίων που αναμένουν τη διεπαφή PSR-11 Container, μπορείτε να δημιουργήσετε έναν απλό προσαρμογέα που θα χρησιμεύσει ως γέφυρα μεταξύ του Nette DI Container και του PSR-11.

έκδοση: 3.x