βασικεσ εννοιεσ αντικειμενοστραφους προγραμματισμου
Object (Αντικείμενο)
Αντικείμενο είναι μία δομή κώδικα με συσχετιζόμενη κατάσταση και συμπεριφορά. Τα αντικείμενα στον προγραμματισμό συχνά χρησιμοποιoύνται για να παραστήσουν πραγματικά αντικείμενα που βρίσκουμε στην καθημερινότητα .Η κατάσταση ενός αντικειμένου περιγράφεται με πεδία(fields), ενώ η συμπεριφορά με κομμάτια κώδικα που ονομάζονται μέθοδοι.
Αντικείμενο είναι μία δομή κώδικα με συσχετιζόμενη κατάσταση και συμπεριφορά. Τα αντικείμενα στον προγραμματισμό συχνά χρησιμοποιoύνται για να παραστήσουν πραγματικά αντικείμενα που βρίσκουμε στην καθημερινότητα .Η κατάσταση ενός αντικειμένου περιγράφεται με πεδία(fields), ενώ η συμπεριφορά με κομμάτια κώδικα που ονομάζονται μέθοδοι.
Αυτή η δομή προγραμματισμού αναπτύχθηκε για να παρέχεται ενθυλάκωση της πληροφορίας κατάστασης ενός αντικειμένου (δηλ των πεδίων) και της συμπεριφοράς του (data encapsulation). Το αντικείμενο ενθυλακώνει την πληροφορία του και ο μόνος τρόπος αλληλεπίδρασης με αυτό είναι μέσω των μεθόδων του(συμπεριφοράς ).
Θεωρείστε το παράδειγμα ενός ποδηλάτου (cadence = ταχύτητα πεντάλ, brake = φρένο, gear = ταχύτητα τροχαλίας)
Θεωρείστε το παράδειγμα ενός ποδηλάτου (cadence = ταχύτητα πεντάλ, brake = φρένο, gear = ταχύτητα τροχαλίας)
Προσδίδοντας κατάσταση (current speed, current pedal cadence, and current gear) και παρέχοντας μεθόδους για την αλλαγή αυτής της κατάστασης το αντικείμενο διατηρεί τον έλεγχο ως προς το πως ο "έξω κόσμος" μπορεί να το χρησιμοποιήσει. Για παράδειγμα, αν το ποδήλατο έχει 6 ταχύτητες, η μέθοδος Change gears μπορεί να απορρίπτει τιμές μικρότερες του μηδενός και μεγαλύτερες του 6.
Τα πλεονεκτήματα αυτού του σχεδιασμού είναι:
Class (Κλάση)
Η κλάση είναι το πρωτότυπο από το οποίο δημιουργούνται τα αντικείμενα. Στον κώδικα μας περιγράφουμε κλάσεις , οι οποίες μετουσιώνονται σε αντικείμενα κατά την εκτέλεση του προγράμματος μας. Από ένα πρωτότυπο (κλάση) μπορούμε να δημιουργήσουμε πολλαπλά στιγμιότυπα (instances) αντικειμένων με διαφορετικές καταστάσεις αλλά ίδια πάντα συμπεριφορά που ορίζεται από την κλάση.
Στην πραγματική ζωή βρίσκουμε πολλά αντικείμενα του ίδιου είδους π.χ. ποδήλατα της ίδιας εταιρίας και του ίδιου μοντέλου, που έχουν κατασκευαστεί με βάση το ίδιο σχέδιο και έχουν τα ίδια ακριβώς εξαρτήματα. Στην αντικειμενοστρεφή λογική το δικό σας ποδήλατο είναι ένα στιγμιότυπο της κλάσης του αντικειμένου ποδήλατο.
Η παρακάτω κλάση Bicycle είναι μια πιθανή υλοποίηση ποδηλάτου.:
class Bicycle
{
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue)
{
cadence = newValue;
}
void changeGear(int newValue)
{
gear = newValue;
}
void speedUp(int increment)
{
speed = speed + increment;
}
void applyBrakes(int decrement)
{
speed = speed - decrement;
}
void printStates()
{
System.out.println("cadence:" + cadence + " speed:" + speed + " gear:" + gear);
}
}
Αφού δημιουργήσουμε μια κλάση μπορούμε να δημιουργήσουμε ένα στιγμιότυπο(object) από αυτή.Ο μόνος τρόπος για να δημιουργηθεί ένα τέτοιο στιγμιότυπο είναι μέσα από τον κώδικα κάποιας άλλης κλάσης. Η αρχική κλάση μιας εφαρμογής περιέχει πάντα τον ορισμό μιας μεθόδου "main" η οποία και εκτελείται πρώτη.Εκεί δημιουργούμε τα πρώτα στιγμιότυπα της εφαρμογής. (Η λέξη κλειδί new χρησιμοποιείται για την δημιουργία στιγμιοτύπων. Θα δούμε αργότερα ακριβώς πώς)
Η κλάση BicycleDemo δημιουργεί δύο Bicycle αντικείμενα και καλεί τις μεθόδους τους:
class BicycleDemo
{
public static void main(String[] args)
{
// Δημιουργία δύο διαφορετικών
// αντικειμένων Bicycle
Bicycle bike1 = new Bicycle();
Bicycle bike2 = new Bicycle();
// Κλήσεις μεθόδων σε
// αυτά τα αντικέιμενα
bike1.changeCadence(50);
bike1.speedUp(10);
bike1.changeGear(2);
bike1.printStates();
bike2.changeCadence(50);
bike2.speedUp(10);
bike2.changeGear(2);
bike2.changeCadence(40);
bike2.speedUp(10);
bike2.changeGear(3);
bike2.printStates();
}
}
Η έξοδος του προγράμματος τυπώνει την τελική ταχύτητα του πεντάλ,ταχύτητα ποδηλάτου και ταχύτητα τροχαλίας για τα δύο ποδήλατα.
cadence:50 speed:10 gear:2 cadence:40 speed:20 gear:3
Inheritance (Κληρονομικότητα)
Η κληρονομικότητα παρέχει ένα ισχυρό και φυσικό τρόπο οργάνωσης και δόμησης του κώδικα. Μια κλάση έχει τη δυνατότητα να κληρονομεί και να προεκτείνει την κατάσταση και τη συμπεριφορά μιας άλλης κλάσης, λεγόμενης και super κλάσης (superclass). Η κλάση αυτή λέγεται τότε subclass της κλάσης αυτής.
Διαφορετικά είδη αντικειμένων έχουν συχνά συγκεκριμένο αριθμό κοινών στοιχείων μεταξύ τους.Τα mountain bike (ποδήλατα ανωμάλου δρόμου), road bike(ποδήλατα δρόμου), και tandem bike (πολυθέσια), για παράδειγμα, μοιράζονται όλα τα κοινά χαρακτηριστικά του ποδηλάτου (speed, pedal cadence, gear).Όμως το κάθε ένα έχει και επιπρόσθετες ιδιότητες π.χ. τα πολυθέσια έχουν περισσότερες θέσεις και χερούλια, τα ποδήλατα δρόμου έχουν κυρτά χερούλια τιμονιού, κάποια ποδήλατα ανωμάλου δρόμου έχουν επιπλέον αλυσίδα για πιο αργές ταχύτητες κτλ.
Ο αντικειμενοστρεφής προγραμματισμός επιτρέπει στις κλάσεις να κληρονομούν κοινά χρησιμοποιούμενη κατάσταση από άλλες κλάσεις. Σε αυτό το παράδειγμα το Bicycle γίνεται η super κλάση των MountainBike, RoadBike, και TandemBike. Στην Java κάθε αντικείμενο μπορεί να έχει μια superclass και μπορεί δυνητικά να έχει απεριόριστο αριθμό subclass.
Τα πλεονεκτήματα αυτού του σχεδιασμού είναι:
- Ατομικότητα: Ο κώδικας ενός αντικειμένου μπορεί να γραφτεί και να συντηρηθεί ανεξάρτητα από τον κώδικα άλλων αντικειμένων. Μόλις δημιουργηθεί ένα αντικείμενο μπορεί να προωθείται εύκολα μέσα στο σύστημα.
- Απόκρυψη Πληροφοριών: Με την αλληλεπίδραση μόνο με τις μεθόδους του αντικειμένου, οι λεπτομέρειες της εσωτερικής υλοποίησης παραμένουν κρυφές από τον έξω κόσμο.
- Επαναχρησιμοποίηση κώδικα: Εάν ένα αντικείμενο υπάρχει ήδη (ενδεχομένως να έχει γραφτεί από άλλο προγραμματιστή), μπορείτε να το χρησιμοποιήσετε στο δικό σας πρόγραμμα Αυτό επιτρέπει σε εξειδικευμένους προγραμματιστές να υλοποιούν/δοκιμάζουν/εκσφαλματώνουν πολύπλοκα και συγκεκριμένης λειτουργίας αντικείμενα, τα οποία μετά μπορεί κάποιος να χρησιμοποιήσει στον δικό του κώδικα.
- Ευκολία σύνθεσης και εκσφαλμάτωσης: Αν ένα συγκεκριμένο αντικείμενο αποδειχθεί προβληματικό, μπορεί κανείς να το αφαιρέσει και να προσθέσει στη θέση του ένα άλλο. Όπως στον πραγματικό κόσμο όταν ένα εξάρτημα μιας μηχανής είναι ακατάλληλο ή προβληματικό, τότε αυτό μπορεί να αντικατασταθεί.
Class (Κλάση)
Η κλάση είναι το πρωτότυπο από το οποίο δημιουργούνται τα αντικείμενα. Στον κώδικα μας περιγράφουμε κλάσεις , οι οποίες μετουσιώνονται σε αντικείμενα κατά την εκτέλεση του προγράμματος μας. Από ένα πρωτότυπο (κλάση) μπορούμε να δημιουργήσουμε πολλαπλά στιγμιότυπα (instances) αντικειμένων με διαφορετικές καταστάσεις αλλά ίδια πάντα συμπεριφορά που ορίζεται από την κλάση.
Στην πραγματική ζωή βρίσκουμε πολλά αντικείμενα του ίδιου είδους π.χ. ποδήλατα της ίδιας εταιρίας και του ίδιου μοντέλου, που έχουν κατασκευαστεί με βάση το ίδιο σχέδιο και έχουν τα ίδια ακριβώς εξαρτήματα. Στην αντικειμενοστρεφή λογική το δικό σας ποδήλατο είναι ένα στιγμιότυπο της κλάσης του αντικειμένου ποδήλατο.
Η παρακάτω κλάση Bicycle είναι μια πιθανή υλοποίηση ποδηλάτου.:
class Bicycle
{
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue)
{
cadence = newValue;
}
void changeGear(int newValue)
{
gear = newValue;
}
void speedUp(int increment)
{
speed = speed + increment;
}
void applyBrakes(int decrement)
{
speed = speed - decrement;
}
void printStates()
{
System.out.println("cadence:" + cadence + " speed:" + speed + " gear:" + gear);
}
}
Αφού δημιουργήσουμε μια κλάση μπορούμε να δημιουργήσουμε ένα στιγμιότυπο(object) από αυτή.Ο μόνος τρόπος για να δημιουργηθεί ένα τέτοιο στιγμιότυπο είναι μέσα από τον κώδικα κάποιας άλλης κλάσης. Η αρχική κλάση μιας εφαρμογής περιέχει πάντα τον ορισμό μιας μεθόδου "main" η οποία και εκτελείται πρώτη.Εκεί δημιουργούμε τα πρώτα στιγμιότυπα της εφαρμογής. (Η λέξη κλειδί new χρησιμοποιείται για την δημιουργία στιγμιοτύπων. Θα δούμε αργότερα ακριβώς πώς)
Η κλάση BicycleDemo δημιουργεί δύο Bicycle αντικείμενα και καλεί τις μεθόδους τους:
class BicycleDemo
{
public static void main(String[] args)
{
// Δημιουργία δύο διαφορετικών
// αντικειμένων Bicycle
Bicycle bike1 = new Bicycle();
Bicycle bike2 = new Bicycle();
// Κλήσεις μεθόδων σε
// αυτά τα αντικέιμενα
bike1.changeCadence(50);
bike1.speedUp(10);
bike1.changeGear(2);
bike1.printStates();
bike2.changeCadence(50);
bike2.speedUp(10);
bike2.changeGear(2);
bike2.changeCadence(40);
bike2.speedUp(10);
bike2.changeGear(3);
bike2.printStates();
}
}
Η έξοδος του προγράμματος τυπώνει την τελική ταχύτητα του πεντάλ,ταχύτητα ποδηλάτου και ταχύτητα τροχαλίας για τα δύο ποδήλατα.
cadence:50 speed:10 gear:2 cadence:40 speed:20 gear:3
Inheritance (Κληρονομικότητα)
Η κληρονομικότητα παρέχει ένα ισχυρό και φυσικό τρόπο οργάνωσης και δόμησης του κώδικα. Μια κλάση έχει τη δυνατότητα να κληρονομεί και να προεκτείνει την κατάσταση και τη συμπεριφορά μιας άλλης κλάσης, λεγόμενης και super κλάσης (superclass). Η κλάση αυτή λέγεται τότε subclass της κλάσης αυτής.
Διαφορετικά είδη αντικειμένων έχουν συχνά συγκεκριμένο αριθμό κοινών στοιχείων μεταξύ τους.Τα mountain bike (ποδήλατα ανωμάλου δρόμου), road bike(ποδήλατα δρόμου), και tandem bike (πολυθέσια), για παράδειγμα, μοιράζονται όλα τα κοινά χαρακτηριστικά του ποδηλάτου (speed, pedal cadence, gear).Όμως το κάθε ένα έχει και επιπρόσθετες ιδιότητες π.χ. τα πολυθέσια έχουν περισσότερες θέσεις και χερούλια, τα ποδήλατα δρόμου έχουν κυρτά χερούλια τιμονιού, κάποια ποδήλατα ανωμάλου δρόμου έχουν επιπλέον αλυσίδα για πιο αργές ταχύτητες κτλ.
Ο αντικειμενοστρεφής προγραμματισμός επιτρέπει στις κλάσεις να κληρονομούν κοινά χρησιμοποιούμενη κατάσταση από άλλες κλάσεις. Σε αυτό το παράδειγμα το Bicycle γίνεται η super κλάση των MountainBike, RoadBike, και TandemBike. Στην Java κάθε αντικείμενο μπορεί να έχει μια superclass και μπορεί δυνητικά να έχει απεριόριστο αριθμό subclass.
Μια ιεραρχία της κλάσης Βicycle.
Η σύνταξη για την δημιουργία μιας subclass είναι απλή. Κατά τη δημιουργία μιας νέας κλάσης χρησιμοποιούμε την λέξη κλειδί extends (προεκτείνει) και στη συνέχεια το όνομα της κλάσης από την οποία κληρονομεί:
class MountainBike extends Bicycle
{
// νέα πεδία και μέθοδοι που ορίζουν
// ένα mountain bike μπαίνουν εδώ
}
Το παραπάνω παράδειγμα δίνει στο MountainBike όλα τα πεδία και τις μεθόδους του Bicycle, και επιπλέον επιτρέπει στις δικές του μεθόδους και πεδία να επικεντρωθούν σε ό,τι το κάνει ξεχωριστό από τα άλλα ποδήλατα. με αυτόν τον τρόπο , ο κώδικας των subclasses διαβάζεται ευκολότερα . Παρόλα αυτά, πρέπει επίσης να δίνουμε σημειώσεις για τις λειτουργίες τις μητρικής κλάσης, αφού ο κώδικας της δεν είναι διαθέσιμος να διαβαστεί.
Interface (Διεπαφή)
Ένα interface θα μπορούσε να χαρακτηριστεί ως ένα συμβόλαιο μεταξύ μίας κλάσης και του υπόλοιπου κόσμου. Όταν μια κλάση υλοποιεί ένα interface, υπόσχεται ότι θα παρέχει τη συμπεριφορά που ορίζει το interface.
Όπως είδαμε παραπάνω, τα αντικείμενα αλληλεπιδρoύν με τον υπόλοιπο κόσμο διαμέσου των μεθόδων που εκθέτουν. Οι μέθοδοι αποτελούν την διεπαφή του αντικειμένου με τον έξω κόσμο (το πρόγραμμα μας), π.χ. τα κουμπιά της τηλεόρασης σας είναι το interface (διεπαφή) μεταξύ εσάς και του ηλεκτρικού κυκλώματος μέσα στο πλαστικό περίβλημα. Πατώντας το κουμπί ενεργοποίησης η συσκευή της τηλεόρασης ανοίγει και κλείνει.
Στην πιο κοινή του μορφή, ένα interface είναι ένα σύνολο από μεθόδους με κενό σώμα. Η συμπεριφορά του ποδηλάτου αν οριστεί με ένα interface έχει ώς εξής:
interface Bicycle
{
// wheel revolutions per minute
void changeCadence(int newValue);
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
}
Για την υλοποίηση ενός interface σε μια κλάση, κατά συνθήκη
class ACMEBicycle implements Bicycle
{
// η κλάση αυτή υλοποιείται όπως παραπάνω
}
Η υλοποίηση ενός interface επιτρέπει σε μια κλάση να είναι πιο τυπική ως προς την συμπεριφορά που υπόσχεται να υλοποιήσει. Αν η κλάση σας υπόσχεται να υλοποιήσει ένα interface, τότε ο compiler επιβάλει οι μέθοδοι του interface να υπάρχουν μέσα στην κλάση αυτή.
Σημείωση: Για να γίνει compile της κλάσης ACMEBicycle, θα πρέπει να προστεθεί η λέξη κλειδί public στην αρχή του ορίσματος κάθε υλοποιούμενης μεθόδου του interface. (η σημασία εξηγείται αργότερα).
Package (Πακέτο)
Το πακέτο (package) είναι ένας χώρος ονομάτων (namespace) που χρησιμοποιείται για την οργάνωση κλάσεων και interface με λογικό τρόπο ώστε να γίνεται ευκολότερη η διαχείριση μεγάλων έργων .
Τα πακέτα ειναι αντίστοιχα με τους φακέλους στο λειτουργικό σύστημα ενός υπολογιστή. To SDK της Java παρέχει μία τεράστια βιβλιοθήκη από έτοιμα πακέτα που μπορεί κανείς να χρησιμοποιήσει, η οποία περιλαμβάνει από διαχείριση αρχείων μέχρι γραφικό περιβάλλον και δικτυακές επικοινωνίες.Στο πρόγραμμά μας μπορούν να χρησιμοποιηθούν λειτουργίες από άλλα πακέτα απλά δηλώνοντας ότι τα χρησιμοποιούμε με την λέξη κλειδί import και το όνομα του πακέτου.
Θα εξηγηθεί παρακάτω η χρήση τους.
Ονοματολογία (Naming)
Για την Java ισχύουν μερικοί άτυποι και τυπικοί κανόνες ονοματολογίας κώδικα .
Η σύνταξη για την δημιουργία μιας subclass είναι απλή. Κατά τη δημιουργία μιας νέας κλάσης χρησιμοποιούμε την λέξη κλειδί extends (προεκτείνει) και στη συνέχεια το όνομα της κλάσης από την οποία κληρονομεί:
class MountainBike extends Bicycle
{
// νέα πεδία και μέθοδοι που ορίζουν
// ένα mountain bike μπαίνουν εδώ
}
Το παραπάνω παράδειγμα δίνει στο MountainBike όλα τα πεδία και τις μεθόδους του Bicycle, και επιπλέον επιτρέπει στις δικές του μεθόδους και πεδία να επικεντρωθούν σε ό,τι το κάνει ξεχωριστό από τα άλλα ποδήλατα. με αυτόν τον τρόπο , ο κώδικας των subclasses διαβάζεται ευκολότερα . Παρόλα αυτά, πρέπει επίσης να δίνουμε σημειώσεις για τις λειτουργίες τις μητρικής κλάσης, αφού ο κώδικας της δεν είναι διαθέσιμος να διαβαστεί.
Interface (Διεπαφή)
Ένα interface θα μπορούσε να χαρακτηριστεί ως ένα συμβόλαιο μεταξύ μίας κλάσης και του υπόλοιπου κόσμου. Όταν μια κλάση υλοποιεί ένα interface, υπόσχεται ότι θα παρέχει τη συμπεριφορά που ορίζει το interface.
Όπως είδαμε παραπάνω, τα αντικείμενα αλληλεπιδρoύν με τον υπόλοιπο κόσμο διαμέσου των μεθόδων που εκθέτουν. Οι μέθοδοι αποτελούν την διεπαφή του αντικειμένου με τον έξω κόσμο (το πρόγραμμα μας), π.χ. τα κουμπιά της τηλεόρασης σας είναι το interface (διεπαφή) μεταξύ εσάς και του ηλεκτρικού κυκλώματος μέσα στο πλαστικό περίβλημα. Πατώντας το κουμπί ενεργοποίησης η συσκευή της τηλεόρασης ανοίγει και κλείνει.
Στην πιο κοινή του μορφή, ένα interface είναι ένα σύνολο από μεθόδους με κενό σώμα. Η συμπεριφορά του ποδηλάτου αν οριστεί με ένα interface έχει ώς εξής:
interface Bicycle
{
// wheel revolutions per minute
void changeCadence(int newValue);
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
}
Για την υλοποίηση ενός interface σε μια κλάση, κατά συνθήκη
- αλλάζουμε το όνομα της (π.χ. σε μια μάρκα ποδηλάτου όπως το ποδήλατο του cartoon RoadRunner ACMEBicycle)
- προσθέτουμε τη λέξη κλειδί implements (υλοποιεί) και το όνομα του interface μετά το όρισμα της κλάσης.
class ACMEBicycle implements Bicycle
{
// η κλάση αυτή υλοποιείται όπως παραπάνω
}
Η υλοποίηση ενός interface επιτρέπει σε μια κλάση να είναι πιο τυπική ως προς την συμπεριφορά που υπόσχεται να υλοποιήσει. Αν η κλάση σας υπόσχεται να υλοποιήσει ένα interface, τότε ο compiler επιβάλει οι μέθοδοι του interface να υπάρχουν μέσα στην κλάση αυτή.
Σημείωση: Για να γίνει compile της κλάσης ACMEBicycle, θα πρέπει να προστεθεί η λέξη κλειδί public στην αρχή του ορίσματος κάθε υλοποιούμενης μεθόδου του interface. (η σημασία εξηγείται αργότερα).
Package (Πακέτο)
Το πακέτο (package) είναι ένας χώρος ονομάτων (namespace) που χρησιμοποιείται για την οργάνωση κλάσεων και interface με λογικό τρόπο ώστε να γίνεται ευκολότερη η διαχείριση μεγάλων έργων .
Τα πακέτα ειναι αντίστοιχα με τους φακέλους στο λειτουργικό σύστημα ενός υπολογιστή. To SDK της Java παρέχει μία τεράστια βιβλιοθήκη από έτοιμα πακέτα που μπορεί κανείς να χρησιμοποιήσει, η οποία περιλαμβάνει από διαχείριση αρχείων μέχρι γραφικό περιβάλλον και δικτυακές επικοινωνίες.Στο πρόγραμμά μας μπορούν να χρησιμοποιηθούν λειτουργίες από άλλα πακέτα απλά δηλώνοντας ότι τα χρησιμοποιούμε με την λέξη κλειδί import και το όνομα του πακέτου.
Θα εξηγηθεί παρακάτω η χρήση τους.
Ονοματολογία (Naming)
Για την Java ισχύουν μερικοί άτυποι και τυπικοί κανόνες ονοματολογίας κώδικα .
- Τα ονόματα που δίδουμε πρέπει να είναι κατά κοινή λογική περιγραφικά. Είναι πάντα μια συνεχόμενη λέξη που μπορεί να απαρτίζεται από πολλά μέρη. π.χ. myImportantVariable
- Τα ονόματα των package συνηθιζεται να έχουν όλα τα γράμματα μικρά. π.χ. mypackage
- Τα ονόματα των κλάσεων ξεκινούν με κεφαλαίο το πρώτο γράμμα ενώ κάθε επιπλέον λέξη με κεφαλαίο γράμμα επίσης. π.χ. MyFantasticClass
- Τα ονόματα των interface συνηθίζεται να ξεκινούν (αλλά όχι υποχρεωτικά) με την λέξη is και να έχουν μορφή επιθέτου . π.χ. isAnImplentableInterface
- Τα ονόματα πεδίων και μεθόδων ξεκινούν πάντα με μικρό αλφαβητικό χαρακτήρα ή κάτω παύλα ( _ ) π.χ. myName ή _myName