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

Σε αυτό το άρθρο, θα μάθετε πώς να μοιράζεστε και να επιβάλλετε κώδικα με πολυμορφισμό χρησιμοποιώντας αφηρημένες τάξεις και διεπαφές.

Θα καταδυθούμε βαθύτερα στον Αντικειμενοστρεφή Προγραμματισμό και θα προσπαθήσουμε να σκεφτούμε από την άποψη των Σχεδίων Σχεδιασμού για να μοιραστούμε και να εφαρμόσουμε τον κώδικα μας χρησιμοποιώντας τον Πολυμορφισμό.

Περίληψη τάξη

Ας πούμε ότι έχουμε μια κατηγορία που ονομάζεται άνθρωπος με ορισμένες ιδιότητες ( name, age, height, fav_drinksκαι fav_sports) και μεθόδους ( giveFirmHandshakes, beStubbornκαι notPutToiletPaper).

name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } }

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

name, $jack->age, $jack->height); // => Jack - 26 - 5 Feet 6 Inches

Τώρα, ας πούμε ότι θέλουμε να προσθέσουμε μια νέα μέθοδο σε αυτήν την τάξη που ονομάζεται isActive.

Αυτή η μέθοδος ελέγχει εάν η ιδιότητα είναι ενεργή και επιστρέφει το κατάλληλο μήνυμα ανάλογα με την τιμή του ενεργού, με προεπιλεγμένη τιμή false. Μπορούμε να το κάνουμε αληθινό για εκείνους τους άνδρες που είναι ενεργοί.

active == true) { return "I am an active man."; } else { return "I am an idle man."; } } } $jack = new Man('Jack', '26', '5 Feet 6 Inches'); $jack->active = true; echo $jack->isActive(); // => I am an active man. $jake = new Man('Jake', '30', '6 Feet'); echo "\n" . $jake->isActive(); // => I am an idle man.

Τι γίνεται αν ένας άντρας δεν είναι απλώς ενεργός ή αδρανής;

Τι γίνεται αν υπάρχει κλίμακα 1 έως 4 που μετρά πόσο ενεργός είναι ένας άντρας (1 - αδράνεια, 2 - ελαφρά ενεργό, 3- μέτρια ενεργό, 4- πολύ ενεργό);

Μπορούμε να έχουμε μια δήλωση if..elseif..else ως εξής:

active == 1) { return "I am an idle man."; } elseif ($this->active == 2) { return "I am a lightly active man."; } elseif ($this->active == 3) { return "I am a moderately active man."; } else { return "I am a very active man."; } }

Τώρα, ας το κάνουμε ένα βήμα παραπέρα.

Τι γίνεται αν η ενεργή ιδιότητα του ανθρώπου δεν είναι απλώς ακέραιος (1, 2, 3, 4, κλπ); Τι γίνεται αν η αξία του ενεργού είναι «αθλητικός» ή «τεμπέλης»;

Δεν χρειάζεται να προσθέσουμε περισσότερες δηλώσεις αν ψάχνετε για αντιστοιχία με αυτές τις χορδές;

Οι αφηρημένες τάξεις μπορούν να χρησιμοποιηθούν για ένα τέτοιο σενάριο.

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

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

Με αυτόν τον τρόπο, θα επιβάλλετε σε όλες τις παιδικές τάξεις να καθορίσουν τη δική τους εκδοχή των αφηρημένων μεθόδων. Ας δούμε πώς μπορούμε να ορίσουμε τη isActive()μέθοδο μας ως αφηρημένη.

1: Ορίστε την τάξη ως αφηρημένη.


    

2: Create an abstract method for the method you want to enforce inside the abstract class.


     

3: Create a child class extending the abstract class.


      

4: Implement the abstract method inside the child class.


       

5: Instantiate the child class (NOT the abstract class).

isActive(); // => I am a very active athlete.

Complete abstract class definition and implementation code:

name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } abstract public function isActive(); } class AthleticMan extends Man { public function isActive() { return "I am a very active athlete."; } } $jack = new AthleticMan('Jack', '26', '5 feet 6 inches'); echo $jack->isActive(); // => I am a very active athlete.

In this code, you will notice that isActive() abstract method is defined inside Man abstract class and it is implemented inside child class AthleticMan.

Now Man class cannot be instantiated directly to create an object.

isActive(); // => Fatal error: Uncaught Error: Cannot instantiate abstract class Man

Also, every child class of the abstract class (Man class) needs to implement all the abstract methods. Lack of such implementation will result in a fatal error.

isActive(); // => Fatal error: Class LazyMan contains 1 abstract method // => and must therefore be declared abstract or implement // => the remaining methods (Man::isActive)

By using abstract classes, you can enforce certain methods to be implemented individually by the child classes.

Interface

There is another Object Oriented Programming concept that is closely related to Abstract Classes called Interface.

The only difference between Abstract Classes and Interfaces is that in Abstract Classes, you can have a mix of defined methods (giveFirmHandshakes(), isStubborn(), etc.) and abstract methods (isActive()) inside the parent class. But in Interfaces, you can only define (not implement) methods inside the parent class.

Let’s see how we can convert Man abstract class above to an interface.

1: Define the interface with all the methods (use interface instead of class).


      

2: Create a class that implements the interface (use implements instead of extends).

This class must implement ALL the methods defined inside the interface including the constructor method.

name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } public function isActive() { return "I am a very active athlete."; } }

3: Instantiate the implementing class (AthleticMan)

isActive(); // => I am a very active athlete.

With interfaces, you need to keep in mind that:

  • The methods cannot be implemented inside the interface.
  • Variables (properties) cannot be defined inside the interface.
  • All the methods defined inside the interface need to be implemented in the child (implementing) class.
  • All the necessary variables need to be defined inside the child class.
  • Man interface enforces its implementing classes to implement all the methods in the interface.

So, what is the use of interfaces?

Can’t we just create a new class AthleticMan and create all the methods instead of implementing the interface?

This is where Design Patterns come into play.

Interfaces are used when there is a base class (Man) that wants to enforce you to do things (construct an object, giveFirmHandshakes, beStubborn, notPutToiletPaper and check if you are active) but doesn’t want to tell you exactly how to do it.

You can just go ahead and create implementing classes with implementations as you deem fit.

As long as all the methods are implemented, Man interface doesn’t care how.

We have gone over how and when to use abstract classes and interfaces in PHP. Using these OOP concepts to have classes with different functionality sharing the same base “blueprint” (abstract class or interface) is called Polymorphism.