23.01.2015 Views

Untitled

Untitled

Untitled

SHOW MORE
SHOW LESS
  • No tags were found...

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Το παρόν εκπονήθηκε στο πλαίσιο<br />

του Υποέργου 6 «Εκπαίδευση επιμορφωτών και βοηθών επιμορφωτών»<br />

της Πράξης «Επαγγελματικό λογισμικό στην ΤΕΕ: επιμόρφωση και εφαρμογή»<br />

(Γ’ ΚΠΣ, ΕΠΕΑΕΚ, Μέτρο 2.3, Ενέργεια 2.3.2)<br />

που συγχρηματοδοτείται από την Ευρωπαϊκή Ένωση / Ευρωπαϊκό Κοινωνικό Ταμείο<br />

Φορέας Υλοποίησης και Τελικός Δικαιούχος<br />

Υπουργείο Εθνικής Παιδείας και Θρησκευμάτων<br />

Ειδική Υπηρεσία Εφαρμογής Προγραμμάτων ΚΠΣ<br />

Φορέας Λειτουργίας<br />

Υπουργείο Εθνικής Παιδείας και Θρησκευμάτων<br />

Διεύθυνση Σπουδών Δευτεροβάθμιας Εκπαίδευσης-Τμήμα Β’<br />

Επιστημονικός Τεχνικός Σύμβουλος<br />

Ερευνητικό Ακαδημαϊκό Ινστιτούτο Τεχνολογίας Υπολογιστών<br />

Υπεύθυνος Πράξης<br />

Βασίλειος Νικολόπουλος<br />

Προϊστάμενος Μονάδας Α1-Ειδική Υπηρεσίας Εφαρμογής Προγραμμάτων ΚΠΣ-ΥπΕΠΘ.


ΕΡΓΟ: «ΑΝΑΠΤΥΞΗ ΜΕΤΑΠΤΥΧΙΑΚΟΥ ΕΚΠΑΙΔΕΥΤΙΚΟΥ ΥΛΙΚΟΥ ΓΙΑ ΕΠΙΜΟΡΦΩΤΕΣ<br />

ΤΕΧΝΟΛΟΓΙΩΝ ΤΗΣ ΠΛΗΡΟΦΟΡΙΑΣ ΚΑΙ ΤΗΣ ΕΠΙΚΟΙΝΩΝΙΑΣ (ΤΠΕ) ΣΤΗΝ ΤΕΧΝΙΚΗ ΚΑΙ<br />

ΕΠΑΓΓΕΛΜΑΤΙΚΗ ΕΚΠΑΙΔΕΥΣΗ (ΤΕΕ), ΑΝΑΠΤΥΞΗ ΕΠΙΜΟΡΦΩΤΙΚΟΥ ΥΛΙΚΟΥ ΓΙΑ<br />

ΣΕΜΙΝΑΡΙΑ ΤΠΕ ΣΤΗΝ ΤΕΕ, ΜΕΤΑΠΤΥΧΙΑΚΗ ΕΚΠΑΙΔΕΥΣΗ ΕΠΙΜΟΡΦΩΤΩΝ ΤΠΕ ΣΤΗΝ ΤΕΕ,<br />

ΚΑΙ ΕΚΠΑΙΔΕΥΣΗ ΥΠΕΥΘΥΝΩΝ ΥΠΟΣΤΗΡΙΞΗΣ ΕΠΙΜΟΡΦΩΤΙΚΩΝ ΣΥΝΑΝΤΗΣΕΩΝ»<br />

Ή ΓΙΑ ΣΥΝΤΟΜΙΑ «Ε2 ΓΙΑ ΤΗΝ ΤΕΕ»<br />

Υπεύθυνοι Έργου<br />

Επιστημονικός Υπεύθυνος του έργου:<br />

Κωνσταντίνος Μακρόπουλος, Καθηγητής του Πανεπιστημίου Αθηνών, Πρόεδρος της<br />

Διοικούσας Επιτροπής της Α.Σ.ΠΑΙ.Τ.Ε.<br />

Αναπληρωτής Επιστημονικός Υπεύθυνος του έργου:<br />

Θεόδωρος Καρτσιώτης, Δρ. Πληροφορικός, Συντονιστής παραγωγής εκπαιδευτικού και<br />

επιμορφωτικού υλικού και Συντονιστής επιμόρφωσης<br />

Υπεύθυνος Διαχείρισης:<br />

Ιωάννης Κ. Ψυχογυιός, Υπεύθυνος Γραφείου Υποστήριξης Ευρωπαϊκών και Ερευνητικών<br />

Προγραμμάτων της Α.Σ.ΠΑΙ.Τ.Ε.<br />

Υπεύθυνος Έργου για το Πανεπιστήμιο Πειραιά:<br />

Συμεών Ρετάλης, Επίκουρος Καθηγητής Πανεπιστημίου Πειραιά<br />

Υπεύθυνη Εκπαιδευτικού Υλικού:<br />

Φωτεινή Παρασκευά, Λέκτορας Πανεπιστημίου Πειραιά<br />

Επιστημονικός συνεργάτης<br />

Εύη Μακρή – Μπότσαρη<br />

Συγγραφική ομάδα<br />

Ανδρέας Παπασαλούρος<br />

Χαρίκλεια Μπούτα<br />

Σεμινάριο Τομέα Πληροφορικής – Δικτύων Η/Υ


ΠΙΝΑΚΑΣ ΠΕΡΙΕΧΟΜΕΝΩΝ<br />

1. ΓΕΝΙΚΑ.................................................................................................6<br />

2. ΈΝΤΑΞΗ ΔΡΑΣΤΗΡΙΟΤΗΤΑΣ ΣΤΟ ΑΝΑΛΥΤΙΚΟ ΠΡΟΓΡΑΜΜΑ ΣΠΟΥΔΩΝ..6<br />

3. ΔΙΔΑΚΤΙΚΟΙ ΣΤΟΧΟΙ ΣΕΜΙΝΑΡΙΟΥ ......................................................6<br />

4. ΑΠΑΡΑΙΤΗΤΟΙ ΤΕΧΝΟΛΟΓΙΚΟΙ ΠΟΡΟΙ .................................................6<br />

5. ΑΝΑΛΥΤΙΚΗ ΠΕΡΙΓΡΑΦΗ ΕΝΟΤΗΤΩΝ....................................................8<br />

Ενότητα 1η:<br />

Εισαγωγή στον Αντικειμενοστρεφή Προγραμματισμό .....................................8<br />

Ενότητα 2η:........................................................................................ 11<br />

Η Java ως αντικειμενοστρεφής γλώσσα προγραμματισμού ........................... 11<br />

Ενότητα 3η:<br />

Μεθοδολογία Ανάπτυξης......................................................................... 23<br />

Ενότητα 4η:<br />

Aνάλυση μιας αυθεντικής κατάστασης ...................................................... 26<br />

Ενότητα 5η:<br />

Σχεδίαση κλάσεων στο BlueJ................................................................... 29<br />

Ενότητα 6η:<br />

Εύρεση ιδιοτήτων και λειτουργιών των κλάσεων ........................................ 33<br />

Ενότητα 7η:<br />

Συγγραφή κώδικα κλάσεων και δημιουργία αντικειμένων............................. 35<br />

Ενότητα 8η:<br />

Ζητήματα αντικειμενοστρεφούς σχεδίασης ................................................ 47<br />

Ενότητα 9η:<br />

Χρήση βιβλιοθήκης γραφικών της Java ..................................................... 49<br />

Ενότητα 10η:<br />

Ανάπτυξη ολοκληρωμένης εφαρμογής ...................................................... 60<br />

Ενότητα 11:<br />

Η διδασκαλία του αντικειμενοστρεφούς προγραμματισμού ........................... 75<br />

Βιβιογραφία ....................................................................................... 79<br />

4


1. Γενικά<br />

Στόχος του εκπαιδευτικού αυτού σεμιναρίου είναι η εισαγωγή στις βασικές έννοιες<br />

του αντικειμενοστρεφούς προγραμματισμού: κλάση, αντικείμενο, ιδιότητες,<br />

μέθοδος, μέθοδος κατασκευαστή, υπερφόρτωση μεθόδων, κληρονομικότητα,<br />

πολυμορφισμός, αφηρημένες κλάσεις-μέθοδοι, κελυφοποίηση, διαπροσωπεία<br />

κλάσης, καθώς το σεμινάριο εστιάζεται σε αυθεντικές καταστάσεις του<br />

πραγματικού κόσμου με πρόσωπα, που επιτελούν ρόλους και έχουν συγκεκριμένες<br />

αρμοδιότητες. Στο σεμινάριο θα χρησιμοποιηθεί η γλώσσα προγραμματισμού Java<br />

και το εκπαιδευτικό περιβάλλον BlueJ. Το σεμινάριο θα περιλαμβάνει σύντομες<br />

παρουσιάσεις θεωρίας, παραδείγματα και δραστηριότητες σκοπός των οποίων είναι<br />

η σχεδίαση και υλοποίηση προγραμμάτων αυξανόμενης δυσκολίας.<br />

2. Ένταξη Σεμιναρίου στο Αναλυτικό Πρόγραμμα Σπουδών<br />

Τάξη: -<br />

Τομέας: -<br />

Ειδικότητα:<br />

Πληροφορικής<br />

Μάθημα: -<br />

Διδακτικές<br />

-<br />

ενότητες:<br />

Διδακτικές ώρες: 36<br />

3. Διδακτικοί Στόχοι Σεμιναρίου<br />

Ως αποτέλεσμα της εκπαιδευτικής διαδικασίας ο επιμορφούμενος αναμένεται:<br />

• Να γνωρίζει έννοιες του αντικειμενοστρεφούς προγραμματιστικού υποδείγματος:<br />

κλάση, αντικείμενο, ιδιότητες, μέθοδος, μέθοδος κατασκευαστή,<br />

υπερφόρτωση μεθόδων, κληρονομικότητα, πολυμορφισμός, αφηρημένες<br />

κλάσεις-μέθοδοι, κελυφοποίηση, διαπροσωπεία κλάσης<br />

• Να γνωρίζει τον τρόπο με τον οποίον αυτές οι έννοιες υποστηρίζονται από τη<br />

γλώσσα προγραμματισμού Java<br />

• Να είναι σε θέση να παράγει ένα αντικειμενοστρεφές σχέδιο για ένα<br />

ρεαλιστικό πεδίο εφαρμογής<br />

• Να υλοποιεί αντικειμενοστρεφή προγράμματα με τη γλώσσα Java<br />

• Με βάση ένα αντικειμενοστρεφές σχέδιο να δημιουργεί ένα πρόγραμμα στη<br />

γλώσσα Java χρησιμοποιώντας το περιβάλλον BlueJ<br />

• Να λύνει ανάλογης φύσης προβλήματα μεταφέροντας τη γνώση που αποκόμισε<br />

• Να γνωρίζει άλλα εκπαιδευτικά περιβάλλοντα για την εκμάθηση του<br />

αντικειμενοστρεφούς προγραμματισμού.<br />

4. Απαραίτητοι Τεχνολογικοί Πόροι<br />

• Εργαστηριακοί χώροι<br />

Το εκπαιδευτικό σενάριο πρέπει να πραγματοποιηθεί σε εργαστηριακό χώρο<br />

στον οποίο θα υπάρχει ένας υπολογιστής ανά επιμορφούμενο.<br />

• Διαδικτυακή υποδομή<br />

5


Το εργαστήριο πληροφορικής του σχολείου.<br />

• Υλικό (Hardware)<br />

Υπολογιστές εργαστηρίου και προαιρετικά χρήση βίντεο.<br />

• Λογισμικά Εργαλεία (Software)<br />

Στο σενάριο χρησιμοποιείται το εκπαιδευτικό προγραμματιστικό περιβάλλον<br />

BlueJ. Προϋπόθεση αποτελεί κατά πρώτο λόγο η εγκατάσταση του Java 2<br />

SDK, έκδοση 1.5, και κατά δεύτερο λόγο του Java 2 SDK Documentation.<br />

Ρόλος Επιμορφωτή<br />

Ο επιμορφωτής παρουσιάζει στους επιμορφούμενους συνοπτικά την απαραίτητη<br />

θεωρία και σχετικά παραδείγματα. Περιγράφει τις δραστηριότητες που πρόκειται να<br />

εκτελέσουν οι επιμορφούμενοι, κάνει υποδείξεις και επιλύει απορίες. Επιπλέον, ο<br />

επιμορφωτής καθορίζει τη σύνθεση των ομάδων και αναθέτει ρόλους στα μέλη<br />

τους.<br />

Περιορισμοί: Σε όλη τη διάρκεια του σεμιναρίου, ο επιμορφωτής φροντίζει να<br />

οριστούν ομάδες ίδιας δυναμικότητας, να ενθαρρύνει την επικοινωνία μεταξύ των<br />

μελών της ομάδας.<br />

Ρόλος Επιμορφούμενου<br />

Οι επιμορφούμενοι χωρίζονται σε ομάδες των τριών ατόμων για την<br />

εκτέλεση των δραστηριοτήτων. Κάθε ομάδα θα σχεδιάσει και θα υλοποιήσει ένα<br />

σύνολο δραστηριοτήτων στο περιβάλλον BlueJ ανεξάρτητα από την άλλη. Κάθε<br />

μέλος μιας ομάδας αναλαμβάνει συγκεκριμένο ρόλο στην ανάπτυξη του έργου.<br />

6


5. Αναλυτική Περιγραφή Ενοτήτων<br />

Ενότητα 1η:<br />

Εισαγωγή στον Αντικειμενοστρεφή Προγραμματισμό<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να γνωρίζουν τις έννοιες κλάση και αντικείμενο.<br />

• Να γνωρίζουν τις βασικές αρχές της αντικειμενοστρεφούς τεχνολογίας.<br />

Η αντικειμενοστρεφής τεχνολογία εμφανίστηκε ως μια προσέγγιση για την<br />

ανάπτυξη λογισμικού με κύριο χαρακτηριστικό την ενοποιημένη αντιμετώπιση των<br />

δεδομένων και των λειτουργιών που εκτελούνται πάνω σε αυτά τα δεδομένα.<br />

Κεντρική έννοια στο αντικειμενοστρεφές παράδειγμα αποτελεί το αντικείμενο<br />

(object). Ένα αντικείμενο είναι μια αναπαράσταση, μια αφαίρεση ενός πράγματος<br />

το οποίο συναντιέται στο πεδίο εφαρμογής για το οποίο κατασκευάζεται το<br />

λογισμικό. Κάθε αντικείμενο έχει κατάσταση, συμπεριφορά και ταυτότητα. Η<br />

κατάσταση περιγράφεται από τις τιμές των ιδιοτήτων δηλαδή των δεδομένων που<br />

σχετίζονται με αυτό το αντικείμενο. Η συμπεριφορά του αντικειμένου υλοποιείται<br />

από τις λειτουργίες ή μεθόδους του αντικειμένου. Μια μέθοδος είναι μια<br />

συνάρτηση ή ένας μετασχηματισμός ο οποίος πραγματοποιείται πάνω στα<br />

δεδομένα ενός αντικειμένου. Μια μέθοδος στην πραγματικότητα χειρίζεται τα<br />

δεδομένα που ανήκουν στο πεδίο ευθύνης του αντικειμένου είτε διαβάζοντας είτε<br />

προσπελάζοντας είτε μεταβάλλοντας αυτά τα δεδομένα. Η ταυτότητα του<br />

αντικειμένου το διαφοροποιεί από τα υπόλοιπα και δεν αποτελεί ιδιότητά του.<br />

Το σύνολο αντικειμένων που έχουν την ίδια δομή και την ίδια συμπεριφορά<br />

ονομάζεται κλάση. Πρέπει να γίνει διάκριση μεταξύ των<br />

εννοιών δομή και κατάσταση. Η δομή χαρακτηρίζεται από<br />

το όνομα και τον τύπο των μεταβλητών που περιγράφουν<br />

τις ιδιότητες του αντικειμένου ενώ η κατάσταση είναι το<br />

σύνολο των συγκεκριμένων τιμών αυτών των μεταβλητών.<br />

Ένα αντικείμενο μιας κλάσης ονομάζεται στιγμιότυπο ή<br />

εμφάνιση (instance) αυτής της κλάσης. Στο διπλανό<br />

σχήμα, το ορθογώνιο πλαίσιο παριστάνει μια κλάση με<br />

χαρακτηριστικά και τις μεθόδους της, τα οποία είναι κοινά<br />

σε όλα τα αντικείμενα της ίδιας κλάσης. Το όνομα και το<br />

Εργαζόμενος<br />

όνομα<br />

έτος_γέννησης<br />

διεύθυνση<br />

εργασία<br />

αλλαγή_εργασίας()<br />

αλλαγή_διεύθυνσης()<br />

έτος_γέννησης είναι ιδιότητες της κλάσης ενώ οι αλλαγή_εργασίας και<br />

αλλαγή_διεύθυνσης είναι μέθοδοί της.<br />

Ο αντικειμενοστρεφής προγραμματισμός είναι μια τεχνική για τη δημιουργία<br />

προγραμμάτων χρησιμοποιώντας αντικείμενα ως δομικές μονάδες των<br />

προγραμμάτων αυτών. Κατά την εκτέλεση ενός τέτοιου προγράμματος, τα<br />

αντικείμενα αλληλεπιδρούν μεταξύ τους επιτελώντας τις λειτουργίες του<br />

προγράμματος. Η δημιουργία των προγραμμάτων συνίσταται στον ορισμό των<br />

κλάσεων των αντικειμένων αυτών υιοθετώντας ένα σύνολο αρχών οι οποίες<br />

περιγράφονται στη συνέχεια. Μια κατηγορία γλωσσών προγραμματισμού έχουν<br />

αναπτυχθεί, οι αντικειμενοστρεφείς γλώσσες προγραμματισμού, οι οποίες<br />

υποστηρίζουν τις αρχές του αντικειμενοστρεφούς προγραμματισμού κατά την<br />

υλοποίηση ενός συστήματος, όπως οι Smalltalk, C++, Java, C#, κ.λπ. Επιπλέον,<br />

αρκετές προγενέστερες γλώσσες προγραμματισμού έχουν ενσωματώσει<br />

αντικειμενοστρεφή χαρακτηριστικά σε νεότερες εκδόσεις τους (π.χ. Lisp, Pascal).<br />

Οι αρχές της αντικειμενοστρεφούς τεχνολογίας είναι δυνατόν να εφαρμοστούν,<br />

πέρα από τον προγραμματισμό, στην ανάλυση και τη σχεδίαση λογισμικού<br />

7


(αντικειμενοστρεφής ανάλυση και σχεδίαση, αντίστοιχα) για τα οποία θα γίνει<br />

λόγος στη συνέχεια του σεμιναρίου. Επιπλέον, ολοκληρωμένες μέθοδοι ανάπτυξης<br />

λογισμικού (software development methods/processes) έχουν αναπτυχθεί<br />

βασισμένες στο αντικειμενοστρεφές παράδειγμα, όπως οι Unified Software<br />

Development Process, Rational Unified Process, Agile/Extreme Programming.<br />

Βασικές αρχές αντικειμενοστρεφούς προγραμματισμού<br />

Στη συνέχεια παρουσιάζονται οι βασικές του αντικειμενοστρεφούς υποδείγματος.<br />

Κάποιες από αυτές τις έννοιες αναφέρονται αποκλειστικά στην αντικειμενοστρεφή<br />

σχεδίαση και τον προγραμματισμό, όπως η κελυφοποίηση και ο πολυμορφισμός,<br />

ενώ άλλες όπως κληρονομικότητα χρησιμοποιούνται και στην ανάλυση. Οι αρχές<br />

αυτές υποστηρίζονται από αντικειμενοστρεφείς γλώσσες προγραμματισμού όπως η<br />

Java με τον τρόπο που θα παρουσιαστεί στη συνέχεια. Επιπλέον, δίνονται στη<br />

συνέχεια του σεμιναρίου αναλυτικά παραδείγματα για την κατανόηση των αρχών<br />

αυτών.<br />

Κληρονομικότητα<br />

Κληρονομικότητα (inheritance) είναι η σχέση μεταξύ δύο κλάσεων όπου η μία<br />

αποδίδει στην άλλη τα χαρακτηριστικά της, ιδιότητες και μεθόδους, και με μια<br />

έννοια της τα κληροδοτεί. Η πρώτη κλάση ονομάζεται κλάση-γονέας ή υπερκλάση<br />

(superclass) και η δεύτερη κλάση-παιδί ή υποκλάση (subclass). H κλάση-παιδί<br />

μπορεί να προσθέσει νέα χαρακτηριστικά σε αυτά που κληρονομεί. Επιπλέον, μια<br />

κλάση-γονέας είναι δυνατόν να έχει περισσότερους από έναν κληρονόμους. Έχει<br />

νόημα, επίσης, η κλάση-παιδί να κληρονομεί περισσότερες από μια κλάση γονέα<br />

(πολλαπλή κληρονομικότητα), αλλά αυτό δημιουργεί στην πράξη προβλήματα και<br />

έτσι δεν υποστηρίζεται ευρέως από τις αντικειμενοστρεφείς γλώσσες<br />

προγραμματισμού (π.χ. την Java). Στην αντικειμενοστρεφή τεχνολογία η κληρονομικότητα<br />

παρέχει ένα μηχανισμό ιεράρχησης (ταξινόμησης) των οντοτήτων του<br />

πραγματικού κόσμου, και επαναχρησιμοποίησης των χαρακτηριστικών και των<br />

λειτουργιών μιας οντότητας λογισμικού.<br />

Κελυφοποίηση, απόκρυψη πληροφοριών<br />

Η κελυφοποίηση (encapsulation) συνδέεται με την ελεγχόμενη πρόσβαση σε<br />

ορισμένα μόνο από τα πεδία και τις μεθόδους μιας κλάσης τα οποία ορίζουν τη<br />

διαπροσωπεία (interface) αυτής της κλάσης προς τον έξω κόσμο. Αυτή είναι η<br />

πρακτική εφαρμογή της απόκρυψης πληροφοριών η οποία αποτελεί βασική αρχή<br />

της αντικειμενοστρεφούς φιλοσοφίας που εφαρμόζεται με διαφορετικούς τρόπους<br />

στις γλώσσες προγραμματισμού οι οποίες την υποστηρίζουν. Η απόκρυψη των<br />

δεδομένων μιας κλάσης επιτρέπει την απόκρυψη του τρόπου εσωτερικής<br />

αναπαράστασης των δεδομένων και του εσωτερικού τρόπου υλοποίησης των<br />

λειτουργιών που παρέχονται από μια κλάση. Για παράδειγμα, μια κλάση που<br />

υλοποιεί μια στοίβα (stack) είναι δυνατόν να αναπαριστά εσωτερικά τη στοίβα με<br />

έναν πίνακα ή μια συνδεδεμένη λίστα. Σύμφωνα με την αρχή της κελυφοποίησης,<br />

αυτή η εσωτερική αναπαράσταση πρέπει να αποκρύπτεται από τους χρήστες αυτής<br />

της κλάσης, η οποία πρέπει να προσπελάζεται μόνο καλώντας τις μεθόδους push<br />

και pop για την εισαγωγή και εξαγωγή στοιχείου από τη στοίβα, αντίστοιχα. Αυτές<br />

ακριβώς οι μέθοδοι συνιστούν τη διαπροσωπεία της κλάσης της στοίβας.<br />

Συνέπεια της κελυφοποίησης είναι η ελαχιστοποίηση των εξαρτήσεων μεταξύ των<br />

μονάδων ενός προγράμματος. Με αυτό τον τρόπο είναι ποιο εύκολο να<br />

τροποποιηθεί τόσο ο κώδικας που καλεί μια κλάση όσο και ο κώδικας της κλάσης<br />

αυτός καθαυτός.<br />

Αφαίρεση<br />

Ο όρος αφαίρεση (abstraction) χρησιμοποιείται με διαφορετικές σημασίες στο<br />

πλαίσιο της αντικειμενοστραφούς τεχνολογίας. Αφαίρεση είναι η εστίαση στα<br />

ουσιαστικά χαρακτηριστικά μιας συγκεκριμένης οντότητας ή ενός συστήματος, τα<br />

8


οποία θεωρούνται σημαντικά από τη σκοπιά από την οποία προσεγγίζεται ένα<br />

πρόβλημα.<br />

Ο ορισμός μιας κλάσης που παριστάνει μια οντότητα ή πράγμα που συναντάται<br />

στον πραγματικό κόσμο συνιστά μια αφαίρεση του πραγματικού κόσμου, σύμφωνα<br />

με την οποία λαμβάνονται υπόψη κάποιες από τις ιδιότητες και τις λειτουργίες<br />

αυτού του πράγματος που έχουν σημασία για το λογισμικό που αναπτύσσεται, ενώ<br />

ενδεχομένως κάποια άλλα χαρακτηριστικά αγνοούνται.<br />

Δύο είδη αφαίρεσης έχουν ιδιαίτερη σημασία: η αφαίρεση διαδικασιών (procedural<br />

abstraction) και η αφαίρεση δεδομένων (data abstraction).<br />

Η αφαίρεση διαδικασιών αναφέρεται στην αντιμετώπιση μιας λειτουργίας (π.χ.<br />

συνάρτησης, υπορουτίνας, μεθόδου κ.λπ. ως ενιαία οντότητα, αγνοώντας το<br />

γεγονός ότι σε ένα κατώτερο επίπεδο αυτή μπορεί να αναλυθεί περεταίρω σε<br />

απλούστερες λειτουργίες. Αυτού του είδους η αφαίρεση δεν είναι χαρακτηριστική<br />

του αντικειμενοστρεφούς προγραμματισμού, καθώς είναι ιδιαίτερα διαδεδομένη και<br />

στον δομημένο προγραμματισμό. Έτσι, ένα πρόγραμμα Pascal είναι δυνατόν να<br />

κατασκευαστεί με βάση αυτή την αρχή.<br />

Η αφαίρεση δεδομένων αναφέρεται στη δυνατότητα δημιουργίας ενός τύπου<br />

δεδομένων μέσω της προδιαγραφής των λειτουργιών που εκτελούνται πάνω στα<br />

αντικείμενα αυτού του τύπου. Ένας τέτοιος τύπος θα μπορούσε να είναι ο Stack ο<br />

οποίος προδιαγράφει τη συμπεριφορά μιας στοίβας μέσω των διαδικασιών<br />

(μεθόδων) push και pop που αναφέρθηκαν προηγουμένως, οι οποίες αναφέρονται<br />

σε δεδομένα αυτού του τύπου. Για κάθε τέτοια προδιαγραφή είναι δυνατές<br />

περισσότερες από μια υλοποιήσεις. Είναι φανερό από τα παραπάνω, ότι η έννοια<br />

της αφαίρεσης δεδομένων σχετίζεται με αυτή της κελυφοποίησης και απόκρυψης<br />

πληροφοριών. Η αφαίρεση δεδομένων σχετίζεται με την παρατηρήσιμη συμπεριφορά<br />

του αντικειμένου, ενώ η κελυφοποίηση αποτρέπει την πρόσβαση στο κομμάτι<br />

της κλάσης που υλοποιεί αυτή τη συμπεριφορά έξω από τα όρια του αντικειμένου.<br />

Επικοινωνία μέσω μηνυμάτων<br />

Σε ένα αντικειμενοστρεφές σύστημα, τα αντικείμενα αλληλεπιδρούν μεταξύ τους<br />

ανταλλάσσοντας μηνύματα. Ένα μήνυμα προς ένα αντικείμενο αντιστοιχεί στην<br />

κλήση μιας μεθόδου που ανήκει στη διαπροσωπεία αυτού του αντικειμένου από<br />

ένα άλλο.<br />

Πολυμορφισμός<br />

Ο πολυμορφισμός (Polymorphism) αναφέρεται στη δυνατότητα της αντικατάστασης<br />

ενός αντικειμένου που ανήκει σε μια κλάση από ένα άλλο που ανήκει σε μια<br />

υποκλάση της πρώτης κατά τη στιγμή της κλήσης μιας μεθόδου. Έτσι, αν ένα<br />

αντικείμενο καλεί τη μέθοδο a() μιας κλάσης Α και η Α1 είναι υποκλάση της Α,<br />

είναι δυνατόν να κληθεί ένα αντικείμενο της κλάσης Α1, ή μιας άλλης που επίσης<br />

κληρονομεί από την Α, στη θέση του αντικειμένου της Α. Αυτή η δυνατότητα<br />

ονομάζεται, ακριβέστερα, πολυμορφισμός υποτύπων (subtype polymorphism) και<br />

αποτελεί βασικό χαρακτηριστικό του αντικειμενοστρεφούς προγραμματιστικού<br />

μοντέλου.<br />

Ένα αντικείμενο είναι δυνατόν να καλεί τη μέθοδο ενός άλλου αντικειμένου με<br />

τέτοιο τρόπο ώστε η κλάση στην οποία ανήκει το δεύτερο να μην είναι γνωστή<br />

κατά το χρόνο μεταγλώττισης, παρά μόνο κατά το χρόνο εκτέλεσης του<br />

προγράμματος. Η δυνατότητα αυτή είναι εφικτή χάρη στο μηχανισμό δυναμικής<br />

δέσμευσης (dynamic binding) ο οποίος παρέχεται από τις υλοποιήσεις αρκετών<br />

αντικειμενοστρεφών γλωσσών προγραμματισμού. Κατά τη δυναμική δέσμευση, η<br />

σύνδεση μιας κλήσης σε μια μέθοδο με την μέθοδο που πραγματικά εκτελείται,<br />

δηλαδή με την πραγματική διεύθυνση της μεθόδου, δεν γίνεται κατά το χρόνο<br />

μεταγλώττισης, αλλά κατά το χρόνο εκτέλεσης του προγράμματος, και<br />

συγκεκριμένα κατά τη στιγμή της κλήσης της μεθόδου. Η χρήση του πολυμορφισμού<br />

θα γίνει ποιο κατανοητή στα παραδείγματα και τις δραστηριότητες του<br />

σεμιναρίου που ακολουθούν.<br />

9


Ενότητα 2η:<br />

Η Java ως αντικειμενοστρεφής γλώσσα προγραμματισμού<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να γνωρίζουν τα βασικά αντικειμενοστρεφή χαρακτηριστικά της Java.<br />

• Να είναι σε θέση να δημιουργούν κλάσεις και διαπροσωπείες στην Java<br />

• Να γνωρίζουν και να χρησιμοποιούν βασικές κλάσεις της Java<br />

Η γλώσσα Java αποτελεί αντικειμενοστρεφή γλώσσα προγραμματισμού και<br />

υποστηρίζει τα χαρακτηριστικά της αντικειμενοστρεφούς φιλοσοφίας που<br />

αναφέρθηκαν παραπάνω. Η σύνταξη της γλώσσας παρουσιάζει πολλές ομοιότητες<br />

με τις προγενέστερες γλώσσες C και C++, αν οι ουσιαστικές διαφορές της Java<br />

από αυτές τις γλώσσες είναι αρκετά μεγάλες. Η Java είναι μια εκτενής γλώσσα<br />

προγραμματισμού. Η παρουσίαση που ακολουθεί καλύπτει στοιχεία της γλώσσας<br />

που είναι χρήσιμα για την υλοποίηση των δραστηριοτήτων του σεμιναρίου με<br />

σκοπό την κατά το δυνατόν αυτόνομη χρήση αυτού του εγχειριδίου. Οι<br />

επιμορφούμενοι μπορούν να ανατρέξουν σε κατάλληλα εγχειρίδια και ιστοσελίδες<br />

στον Ιστό για την περαιτέρω μελέτη της γλώσσας. Μερικά τέτοια εγχειρίδια<br />

παρατίθενται στη βιβλιογραφία. Να σημειωθεί ότι οι βιβλιογραφικές αναφορές δεν<br />

αφορούν όλες στην έκδοση 1.5 της Java, η οποία χρησιμοποιείται στο σεμινάριο<br />

και αποτελεί την ποιο πρόσφατη επίσημη έκδοση της γλώσσας, αλλά, ενδεχομένως,<br />

και σε παλαιότερες εκδόσεις, οι οποίες πάντως είναι συμβατές με την<br />

τελευταία.<br />

Πρέπει να σημειωθεί ότι η απλή χρήση μιας αντικειμενοστρεφούς γλώσσας<br />

προγραμματισμού όπως η Java ή η C++ δεν εξασφαλίζει ότι η σχεδίαση του<br />

προγράμματος ή το ίδιο το πρόγραμμα είναι αντικειμενοστρεφής. Για παράδειγμα,<br />

είναι δυνατή η υλοποίηση ενός προγράμματος ως μια και μοναδική κλάση όπου<br />

όλες οι λειτουργίες του προγράμματος εκτελούνται από τις μεθόδους της μιας<br />

αυτής κλάσης, οι οποίες καλούν η μία την άλλη. Σε αυτή την περίπτωση, το<br />

πρόγραμμα δεν εκτελείται ως ένα σύνολο αντικειμένων που αλληλεπιδρούν, όπως<br />

αναφέρθηκε προηγουμένως ότι συμβαίνει στο αντικειμενοστρεφές μοντέλο, αλλά<br />

ως μια ιεραρχία κλήσεων μεταξύ συναρτήσεων, όπως συμβαίνει στις διαδικαστικές<br />

γλώσσες προγραμματισμού (C, Pascal, κ.λπ.). Ακόμη χειρότερα, το πρόγραμμα<br />

είναι δυνατόν να αποτελείται από κώδικα μιας και μόνης μεθόδου (π.χ. της<br />

μεθόδου main). Για το λόγο αυτόν είναι χρήσιμο να ακολουθούνται οι σχεδιαστικές<br />

αρχές που θα παρουσιαστούν αργότερα σε αυτό το εγχειρίδιο και επιδεικνύονται<br />

στα παραδείγματα του σεμιναρίου.<br />

Αντικειμενοστρεφή χαρακτηριστικά της Java<br />

Ορισμός Κλάσεων<br />

Στη συνέχεια δίνεται ένα παράδειγμα του ορισμού μιας κλάσης στη γλώσσα Java.<br />

public class Point<br />

{<br />

//Πεδία της κλάσης<br />

private int x;<br />

private int y;<br />

//Μέθοδοι της κλάσης<br />

public void setX(int x1)<br />

{<br />

10


}<br />

x = x1;<br />

public void getX()<br />

{<br />

return x;<br />

}<br />

}<br />

//…<br />

Ο ορισμός μιας κλάσης περιέχει δηλώσεις των πεδίων (fields) και των μεθόδων<br />

(methods) της κλάσης. Τα πεδία και οι μέθοδοι ονομάζονται μέλη (members) της<br />

κλάσης.<br />

Οι τύποι των πεδίων μιας κλάσης, όπως και κάθε μεταβλητής που δηλώνεται στη<br />

γλώσσα είναι δύο ειδών: Βασικοί (primitive) τύποι, π.χ. int, char, long, double<br />

και τύποι αναφοράς (reference types), όπως πίνακες, συμβολοσειρές, κ.λπ. οι<br />

οποίοι αποτελούν αναφορές σε αντικείμενα.<br />

Ορατότητα<br />

Η ορατότητα των μελών μιας κλάσης, πεδίων και μεθόδων, δηλαδή η δυνατότητα<br />

προσπέλασης των μελών από κώδικα άλλων κλάσεων προσδιορίζεται από τους<br />

προσδιοριστές ορατότητας ως εξής:<br />

• public. Τα μέλη που δηλώνονται ως public είναι προσβάσιμα από κάθε<br />

κλάση<br />

• private. Τα μέλη είναι προσβάσιμα μόνο από κώδικα της ίδιας κλάσης<br />

• protected. Τα μέλη είναι προσβάσιμα από κώδικα της ίδιας κλάσης ή των<br />

υποκλάσεών της<br />

• Η απουσία προσδιοριστή ορατότητας κατά τη δήλωση ενός μέλους, πεδίου<br />

ή μεθόδου, ορίζει τη λεγόμενη ορατότητα πακέτου (package visibility),<br />

σύμφωνα με την οποία το πεδίο ή μέθοδος είναι προσπελάσιμο μέσα στα<br />

όρια του πακέτου στο οποίο ανήκει η κλάση. Το πακέτο αποτελεί μηχανισμό<br />

ομαδοποίησης που περιγράφεται παρακάτω.<br />

Μέσω των προσδιοριστών ορατότητας υποστηρίζεται η κελυφοποίηση, σύμφωνα<br />

με όσα αναφέρθηκαν προηγουμένως.<br />

Ένα αρχείο πηγαίου κώδικα στην Java είναι δυνατόν να περιέχει τον ορισμό μιας ή<br />

περισσοτέρων κλάσεων. Το όνομα του αρχείου πρέπει να ταυτίζεται με το όνομα<br />

μιας public κλάσης που παριέχεται στο αρχείο. Στην παραπάνω περίπτωση, το<br />

αρχείο πηγαίου κώδικα πρέπει να ονομάζεται Point.java. Σημειώστε ότι ο<br />

μεταγλωττιστής της Java διακρίνει τα μικρά από τα κεφαλαία γράμματα στα<br />

ονόματα των αρχείων, έτσι το πρώτο γράμμα του αρχείου πρέπει να διατηρηθεί<br />

κεφαλαίο.<br />

Δημιουργία αντικειμένων<br />

Αφού οριστεί μια κλάση είναι δυνατόν να κατασκευαστούν αντικείμενα που<br />

προέρχονται από αυτήν. Τα αντικείμενα αυτά αποτελούν στιγμιότυπα ή εμφανίσεις<br />

(instances) της κλάσης αυτής. Για να κατασκευαστεί ένα αντικείμενο απαιτούνται<br />

συνήθως δυο βήματα:<br />

• Δήλωση μιας μεταβλητής με τύπο αναφοράς η οποία θα αναφέρεται στο<br />

αντικείμενο που θα κατασκευαστεί. Για παράδειγμα<br />

Point p;<br />

Η δήλωση αυτή δεν κατασκευάζει κανένα αντικείμενο. Η τιμή της<br />

μεταβλητής p παίρνει την ειδική τιμή null. Γενικά αυτή η ειδική τιμή<br />

11


περιέχεται σε μια μεταβλητή αναφορέας η οποία δεν αναφέρεται σε κάποιο<br />

αντικείμενο.<br />

• Κατασκευή του αντικειμένου με χρήση του τελεστή new.<br />

p = new Point();<br />

Τα δυο βήματα μπορούν να συνενωθούν σε μια δήλωση ως εξής:<br />

Point p = new Point();<br />

Το αντικείμενο μπορεί να χρησιμοποιηθεί μέσω της αναφοράς που αποθηκεύεται<br />

στη μεταβλητή p.<br />

Κλήση μεθόδων<br />

Έστω ότι μια κλάση περιέχει μια μεταβλητή που αναφέρεται σε ένα αντικείμενο της<br />

ίδιας ή μιας άλλης κλάσης. Η εκτέλεση μιας μεθόδου της δεύτερης γίνεται<br />

σύμφωνα με το παρακάτω παράδειγμα:<br />

Point p = new P();<br />

//Κλήση μεθόδου της κλάσης P<br />

p.setX(1);<br />

Είναι δυνατόν να υπάρχουν περισσότερες από μια αναφορές στο ίδιο αντικείμενο,<br />

όπως φαίνεται στο παρακάτω παράδειγμα<br />

Point p2 = p;<br />

p2.setX(1);<br />

p.setX(10);<br />

if (p2.getX() != 10)<br />

{//Αδύνατον…}<br />

Φυσικά, είναι δυνατόν οι δύο μεταβλητές, p και p2, να αναφέρονται σε<br />

διαφορετικά αντικείμενα της ίδιας κλάσης.<br />

Η λέξη this<br />

Με τη λέξη this ένα αντικείμενο μπορεί να αναφέρεται στον εαυτό του. Η λέξη<br />

this χρησιμοποιείται μέσα σε μια μέθοδο ως μια αναφορά του αντικειμένου που<br />

καλεί τη μέθοδο στον εαυτό του. Μια συνηθισμένη χρήση της λέξης φαίνεται στο<br />

παρακάτω παράδειγμα<br />

public void p(int x) { this.x = x; }<br />

Η έκφραση this.x αναφέρεται στο πεδίο x της κλάσης, ώστε αυτό να διακρίνεται<br />

από την παράμετρο x της μεθόδου που έχει το ίδιο όνομα.<br />

Ισότητα αντικειμένων<br />

Ο έλεγχος της ισότητας δύο μεταβλητών που αναφέρονται σε αντικείμενα (μεταβλητές<br />

αναφοράς) είναι δυνατόν να πραγματοποιηθεί με δυο τρόπους:<br />

12


α. Με χρήση του τελεστή ==. Σε αυτή την περίπτωση ελέγχεται αν οι δύο<br />

μεταβλητές αναφέρονται στο ίδιο αντικείμενο.<br />

β. Με χρήση της μεθόδου equals. Η μέθοδος αυτή υλοποιείται από όλα τα<br />

αντικείμενα, καθώς κληρονομείται από την κλάση Object όπως θα αναφερθεί στη<br />

συνέχεια. Κάθε κλάση είναι δυνατόν να την υλοποιεί με διαφορετικό τρόπο.<br />

Κατασκευαστές (constructors)<br />

Η κατασκευή ενός αντικειμένου με τον τελεστή new προκαλεί την αρχικοποίηση<br />

των μεταβλητών αυτού του αντικειμένου. Οι τιμές που χρησιμοποιούνται για την<br />

αρχικοποίηση μπορούν να καθοριστούν κατά τη δήλωση των μεταβλητών, αλλιώς<br />

αρχικοποιούνται αυτόματα σε καθορισμένες τιμές. Μερικές φορές η αρχικοποίηση<br />

δεν είναι δυνατόν να πραγματοποιηθεί με τον τρόπο αυτό. Την ανάγκη αυτή<br />

καλύπτει ένα ιδιαίτερο είδος μεθόδου που ονομάζεται κατασκευαστής<br />

(constructor). Οι κατασκευαστές είναι μέθοδοι που έχουν το όνομα της αντίστοιχης<br />

κλάσης. Μπορούν να έχουν παραμέτρους αλλά δεν επιστρέφουν αποτέλεσμα. Στο<br />

ακόλουθο τμήμα κώδικα ορίζεται πάλι η κλάση Point συμπεριλαμβάνοντας έναν<br />

κατασκευαστή. Αυτός δέχεται ως παραμέτρους τις αρχικές συντεταγμένες του<br />

σημείου.<br />

class Point<br />

{<br />

int x,y ;<br />

Point (int xx,int yy) {x=xx ;y=yy ;}<br />

//...<br />

}<br />

Η αρχικοποίηση του αντικειμένου γίνεται τότε ως εξής<br />

Point p = new Point(100, 200);<br />

static πεδία και μέθοδοι<br />

Κάποια πεδία ή μέθοδοι δεν αναφέρονται σε κάποιο συγκεκριμένο αντικείμενο μιας<br />

κλάσης αλλά στην ίδια την κλάση, ανεξάρτητα από τα αντικείμενα που θα<br />

δημιουργηθούν. Αυτά δηλώνονται με τη λέξη static. Για παράδειγμα, η κλάση<br />

Point είναι δυνατόν να περιέχει το πεδίο<br />

static int numOfPoints;<br />

το οποίο δηλώνει τον αριθμό των σημείων που έχουν δημιουργηθεί συνολικά.<br />

Είναι προφανές ότι η τιμή στην οποία αναφέρεται το πεδίο δεν αναφέρεται σε ένα<br />

συγκεκριμένο σημείο. Μια μέθοδος δηλώνεται επίσης ως static όταν αναφέρεται<br />

στην κλάση στην οποία ανήκει και όχι σε κάποιο στιγμιότυπό (αντικείμενό) της. Για<br />

παράδειγμα έστω η κλάση Num<br />

public class Num {<br />

public static int gcd(int n, int d) {/* Υλοποίηση… */}<br />

}<br />

Η μέθοδος gcd επιστρέφει το μέγιστο κοινό διαιρέτη των ακεραίων n και d. Είναι<br />

προφανές ότι η μέθοδος δεν αναφέρεται σε κάποιο συγκεκριμένο αντικείμενο της<br />

κλάσης Num και έτσι δηλώνεται ως static. Η προσπέλαση σε ένα static πεδίο ή<br />

μέθοδο γίνεται μέσω του ονόματος της κλάσης ως εξής:<br />

13


int myGcd = Num.gcd(10,5);<br />

Καταστροφή αντικειμένων<br />

Αντίθετα με την κατασκευή αντικειμένων, που πρέπει να γίνει ρητά μέσα στον<br />

κώδικα με χρήση του τελεστή new, η καταστροφή αντικειμένων γίνεται αυτόματα<br />

από το περιβάλλον εκτέλεσης της Java όταν τα αντικείμενα πάψουν να<br />

χρησιμοποιούνται. Το περιβάλλον εκτέλεσης θεωρεί ότι ένα αντικείμενο παύει να<br />

χρησιμοποιείται όταν δεν υπάρχει καμία μεταβλητή που να περιέχει αναφορά σε<br />

αυτό.<br />

Πίνακες<br />

Οι πίνακες, όπως και σε άλλες γλώσσες προγραμματισμού, αποτελούν δομές για<br />

την αποθήκευση τιμών που έχουν τον ίδιο τύπο. Το μέγεθος ενός πίνακα<br />

καθορίζεται κατά τη δημιουργία του πίνακα και στη συνέχεια παραμένει σταθερό.<br />

Στην γλώσσα Java οι πίνακες είναι ειδικού τύπου αντικείμενα τα οποία δηλώνονται<br />

και αρχικοποιούνται σε δύο βήματα, όπως ισχύει για όλα τα αντικείμενα:<br />

// Δήλωση της μεταβλητής points ως πίνακα σημείων.<br />

Point points[]; // ή, ισοδύναμα: Point[] points;<br />

// Αρχικοποίηση και καθορισμός μεγέθους του πίνακα.<br />

points = new Point[10];<br />

// Απόδοση τιμής στα στοιχεία του πίνακα. Το πεδίο<br />

// length περιέχει το μέγεθος του πίνακα.<br />

for (int i = 0; i < points.length; i++)<br />

points[i] = new Point(i,i);<br />

Είναι δυνατή η δημιουργία πινάκων με περισσότερες από μια διαστάσεις.<br />

Κληρονομικότητα<br />

Όπως αναφέρθηκε προηγουμένως, ένα από τα βασικά χαρακτηριστικά του μοντέλου<br />

αντικειμενοστρεφούς ανάπτυξης είναι η υποστήριξη της κληρονομικότητας<br />

(inheritance).<br />

Για παράδειγμα, ας υποτεθεί ότι η κλάση Point που ορίστηκε προηγουμένως έχει<br />

χρησιμοποιηθεί σε έναν αριθμό εφαρμογών. Κάποια στιγμή όμως, σε μια νέα<br />

εφαρμογή παρουσιάζεται η ανάγκη για σημεία τα οποία έχουν ένα συγκεκριμένο<br />

χρώμα.<br />

Ο μηχανισμός της κληρονομικότητας παρέχει έναν τρόπο για την επαναχρησιμοποίηση<br />

και την επέκταση της υπάρχουσας κλάσης, χωρίς την αλλαγή του κώδικά<br />

της, όπως φαίνεται παρακάτω παράδειγμα:<br />

class ColoredPoint extends Point {<br />

int color;<br />

}<br />

void setColor(int c)<br />

{<br />

this.color = c;<br />

}<br />

14


Με τη δήλωση extends Point ορίζεται ότι η κλάση ColoredPoint αποτελεί<br />

επέκταση της κλάσης Point. Αυτό σημαίνει ότι κληρονομεί τις ιδιότητες και τις<br />

μεθόδους της Point. Στην ουσία τα αντικείμενα της κλάσης ColoredPoint<br />

μπορούν να χρησιμοποιηθούν οπουδήποτε είναι δυνατή η χρήση αντικειμένων της<br />

κλάσης Point. ή αλλιώς, κάθε αντικείμενο της ColoredPoint είναι Point. Η<br />

υπερκλάση Point ονομάζεται βάση (base class) ενώ η υποκλάση ColoredPoint<br />

ονομάζεται παραγόμενη (derived class). Με βάση το μηχανισμό της κληρονομικότητας<br />

είναι δυνατή η κατασκευή ιεραρχιών κλάσεων, καθώς μια παραγόμενη<br />

κλάση μπορεί με τη σειρά της να αποτελεί κλάση βάσης για νέες παραγωγές. Η<br />

ιεραρχία κλάσεων της Java έχει τη μορφή δέντρου. Στην κορυφή του δέντρου<br />

βρίσκεται μια ειδική κλάση, η Object. Ας σημειωθεί ότι η κληρονομικότητα<br />

υποστηρίζεται τόσο μεταξύ κλάσεων όσο και μεταξύ διαπροσωπειών, οι οποίες<br />

παρουσιάζονται στη συνέχεια. Μια κλάση επιτρέπεται να έχει μόνο μια βασική<br />

κλάση, δηλαδή δεν επιτρέπεται στην Java η πολλαπλή κληρονομικότητα κλάσεων.<br />

Κατά τον ορισμό του κατασκευαστή μιας υποκλάσης, είναι δυνατόν να κληθεί ο<br />

κατασκευαστής της υπερκλάσης με χρήση της λέξης super:<br />

public ColoredPoint(int x, int y,int color)<br />

{<br />

// Κλήση του κατασκευαστή της Point<br />

super(x,y);<br />

this.color = color;<br />

}<br />

Αφηρημένες κλάσεις<br />

Οποιαδήποτε μέθοδος στον ορισμό μιας κλάσης είναι δυνατόν να δηλωθεί ως<br />

αφηρημένη (abstract). Οι αφηρημένες μέθοδοι δεν έχουν σώμα παρά μόνο<br />

επικεφαλίδα όπου δηλώνεται το όνομα της μεθόδου, η επιστρεφόμενη τιμή και οι<br />

παράμετροι της μεθόδου 1 . Με άλλα λόγια, καθορίζεται ο τρόπος χρήσης της<br />

μεθόδου και όχι η υλοποίησή της. Κλάσεις που περιέχουν ή κληρονομούν<br />

αφηρημένες μεθόδους ονομάζονται επίσης αφηρημένες κλάσεις. Οι αφηρημένες<br />

κλάσεις αποτελούν στην πραγματικότητα μερικώς υλοποιημένες κλάσεις, που απλά<br />

προδιαγράφουν ένα τμήμα της λειτουργικότητάς τους αφήνοντας να το<br />

υλοποιήσουν οι υποκλάσεις τους.<br />

abstract class Point {<br />

int x = 1, y = 1;<br />

void move(int dx, int dy) {<br />

x += dx;<br />

y += dy;<br />

alert();<br />

}<br />

//Δήλωση της αφηρημένης μεθόδου alert<br />

abstract void alert();<br />

}<br />

class SimplePoint extends Point {<br />

void alert() {/* Κάνε κάτι συγκεκριμένο */}<br />

1 Η επικεφαλίδα μιας μεθόδου ορίζει επίσης εξαιρέσεις (Exceptions), οι οποίες δεν αναφέρονται σε αυτό<br />

το σεμινάριο.<br />

15


}<br />

Δεν επιτρέπεται η αρχικοποίηση μιας αφηρημένης κλάσης, με άλλα λόγια η εντολή<br />

Point p = new Point();<br />

δεν είναι αποδεκτή από το μεταγλωττιστή της Java. Αντίθετα, αποδεκτή είναι η<br />

εντολή:<br />

Point p = new SimplePoint();<br />

Διαπροσωπείες<br />

Μια διαπροσωπεία (interface) στην Java μπορεί να θεωρηθεί ως μια αφηρημένη<br />

κλάση, η οποία δεν περιέχει μεταβλητές ως πεδία και όλες οι μέθοδοί της είναι<br />

αφηρημένες. Οι διαπροσωπείες, όπως και οι κλάσεις, ορίζουν ιεραρχίες<br />

κληρονομικότητας και είναι δυνατό να δηλωθούν μεταβλητές με τύπο αναφοράς<br />

σε αυτές. Με την έννοια αυτή αποτελούν πλήρως αφηρημένες κλάσεις. Οι<br />

διαπροσωπείες είναι δυνατόν να περιέχουν ως πεδία σταθερές, τα οποία<br />

θεωρούνται ως static και final και πρέπει να αρχικοποιούνται σε συγκεκριμένες<br />

τιμές. Μια κλάση είναι δυνατόν να υλοποιεί περισσότερες από μια διαπροσωπείες.<br />

Μια κλάση η οποία υλοποιεί μια διαπροσωπεία επιβάλλεται να υλοποιεί όλες τις<br />

μεθόδους αυτής της διαπροσωπείας.<br />

Ένα παράδειγμα διαπροσωπείας που προδιαγράφει τη λειτουργία μιας στοίβας<br />

ακεραίων με δεδομένο μέγεθος δίνεται στο παρακάτω παράδειγμα,:<br />

interface IntStack{<br />

/* Πρόκειται για static final πεδίο.<br />

Η τιμή size είναι σταθερή */<br />

int size = 20;<br />

}<br />

public void push(int x);<br />

public int pop();<br />

public boolean full();<br />

public boolean empty();<br />

Μια κλάση που υλοποιεί την διαπροσωπεία MyStack είναι η IntStackImpl:<br />

class IntStackImpl implements IntStack<br />

{<br />

int [] stack = new int[size];<br />

int sp ;<br />

IntStackImpl() {sp = 0;}<br />

public void push(int x)<br />

{<br />

stack[sp] = x;<br />

sp++; // ή sp = sp + 1;<br />

16


}<br />

public int pop()<br />

{<br />

sp--; // ή sp = sp – 1;<br />

int x = stack[sp];<br />

return x;<br />

}<br />

public boolean full() {return (sp == size ); }<br />

}<br />

public boolean empty(){return (sp == 0);}<br />

Είναι δυνατή η χρήση της διαπροσωπείας με μια δήλωση της μορφής<br />

IntStack stack = new IntStackImpl();<br />

If (!stack.full())<br />

push(10);<br />

//…<br />

Μια διαπροσωπεία δεν παρέχει την υλοποίηση παρά μόνο την προδιαγραφή μιας ή<br />

περισσότερων λειτουργιών. Αυτή η διάκριση μεταξύ προδιαγραφής και υλοποίησης<br />

έχει ιδιαίτερη σημασία κατά τη σχεδίαση λογισμικού. Η προδιαγραφή αποτελεί μια<br />

συμφωνία μεταξύ της κλάσης που υλοποιεί αυτή την προδιαγραφή και των<br />

κλάσεων που την χρησιμοποιούν (κλάσεις πελάτες). Έτσι, περισσότερες από μια<br />

κλάσεις είναι δυνατόν να υλοποιούν τη λειτουργικότητα που ορίζει μια<br />

διαπροσωπεία και με ενδεχομένως διαφορετικούς τρόπους. Οι διαπροσωπείες<br />

αποτελούν μηχανισμό για την υποστήριξη της αρχής της αφαίρεσης δεδομένων<br />

από την Java, σύμφωνα με αυτά που αναφέρθηκαν σε προηγούμενη ενότητα,<br />

καθώς επιτρέπουν τον διαχωρισμό της προδιαγραφής της συμπεριφοράς ενός<br />

αντικειμένου (μέσω της διαπροσωπείας που αποτελεί τον τύπο του δεδομένου) από<br />

την υλοποίηση αυτής της συμπεριφοράς. Οι διαπροσωπείες της Java δεν πρέπει να<br />

συγχέονται με την έννοια της διαπροσωπείας μιας κλάσης, η οποία αναφέρθηκε<br />

παραπάνω και η οποία δηλώνει το σύνολο των μεθόδων και των πεδίων της<br />

κλάσης που είναι ορατές έξω από τα όρια της κλάσης.<br />

Υπερφόρτωση και υπέρβαση (υπερίσχυση) μεθόδων<br />

Στην Java επιτρέπεται ο ορισμός μιας μεθόδου με το ίδιο όνομα και επιστρεφόμενη<br />

τιμή αλλά με διαφορετικό αριθμό ή τύπο παραμέτρων. Η δυνατότητα αυτή<br />

αναφέρεται ως υπερφόρτωση μεθόδων (method overloading). Επιπλέον,<br />

επιτρέπεται η υπερφόρτωση των μεθόδων κατασκευαστών.<br />

Μια μέθοδος (που δεν είναι static) μιας υποκλάσης με τον ίδιο όνομα, αριθμό και<br />

τύπο παραμέτρων και τον ίδιο τύπο επιστροφής) με μια μη static μέθοδο μιας<br />

υπερκλάσης της, υπερισχεύει (override) την μέθοδο της υπερκλάσης της.<br />

Με το μηχανισμό της υπερίσχυσης υποστηρίζεται από τη γλώσσα Java το<br />

αντικειμενοστρεφές χαρακτηριστικό του πολυμορφισμού. Για μια δεδομένη<br />

ιεραρχία κλάσεων, είναι πιθανό διαφορετικές υποκλάσεις να κληρονομούν την ίδια<br />

κοινή υπερκλάση. Κάθε μιας από τις υποκλάσεις είναι δυνατόν να «συμπεριφέρεται»<br />

διαφορετικά κατά την λήψη του ίδιου μηνύματος από τις υπόλοιπες<br />

κλάσεις της ιεραρχίας.<br />

17


Πακέτα<br />

Τα πακέτα (packages) στην Java παρέχουν ένα μηχανισμό οργάνωσης των<br />

κλάσεων. Κάθε πακέτο περιέχει ένα αριθμό κλάσεων ή άλλων πακέτων και<br />

προσδιορίζεται από το όνομά του. Οι ορισμοί αυτών των κλάσεων μπορούν να<br />

περιέχονται σε ένα ή περισσότερα αρχεία. Τα ονόματα των πακέτων απαρτίζονται<br />

από μια ή περισσότερες λέξεις, χωρισμένες με τελείες. Για παράδειγμα, ονόματα<br />

πακέτων που χρησιμοποιούνται συχνά στην πράξη είναι τα java.lang και<br />

java.util. Τα πακέτα αποτελούν μηχανισμό κελυφοποίησης καθώς και διαχείρισης<br />

ονομάτων των κλάσεων των προγραμμάτων.<br />

Προκειμένου να χρησιμοποιηθούν τα περιεχόμενα ενός πακέτου, πρέπει το όνομα<br />

του πακέτου να προηγείται του ονόματος της κλάσης. Το ακόλουθο τμήμα κώδικα<br />

χρησιμοποιεί την κλάση Stack που βρίσκεται στο πακέτο java.util.<br />

java.util.Stack s = new java.util.Stack();<br />

MyObject m = new MyObject();<br />

s.push(m);<br />

Για να αποφεύγεται η επανάληψη των μεγάλων ονομάτων των πακέτων, είναι<br />

δυνατόν τα περιεχόμενα του πακέτου να «εισαχθούν» στον κώδικα ώστε να μην<br />

απαιτείται η χρήση του ονόματος του πακέτου. Αυτό γίνεται με τη δήλωση import<br />

η οποία πρέπει να βρίσκεται στην αρχή του αρχείου:<br />

import java.util.Stack;<br />

...<br />

Stack s = new Stack();<br />

Με παρόμοιο τρόπο είναι δυνατόν να εισαχθούν όλα τα περιεχόμενα ενός πακέτου<br />

χρησιμοποιώντας τον ειδικό χαρακτήρα * ως εξής:<br />

import java.util.*;<br />

Ας σημειωθεί ότι η δήλωση import έχει πληροφοριακό χαρακτήρα και δεν<br />

μεταβάλλει το μέγεθος του μεταγλωττισμένου αρχείου.<br />

Βοηθητικές κλάσεις<br />

Συμβολοσειρές (Strings)<br />

Οι συμβολοσειρές αναπαρίστανται στη γλώσσα Java ως αντικείμενα μιας ειδικής<br />

κλάσης, της java.lang.String. Κάθε συμβολοσειρά αποτελεί ένα διαφορετικό<br />

αντικείμενο το οποίο αρχικοποιείται είτε με χρήση των κατασκευαστών της κλάσης,<br />

π.χ.<br />

String iosIsland = new String(“Ίος”);<br />

είτε με ανάθεση<br />

String iosIsland= “Ίος”;<br />

18


Οι συμβολοσειρές είναι ισοδύναμες με πίνακες χαρακτήρων (char), έτσι ώστε το<br />

παραπάνω αντικείμενο είναι ισοδύναμο με το<br />

char[] islandArray = {’Ι’,’ο’,’ς’};<br />

String iosIsland = new String(islandArray);<br />

Η κλάση String περιέχει ένα σύνολο μεθόδων για το χειρισμό συμβολοσειρών.<br />

Σημαντικότερες είναι η length() που επιστρέφει το μέγεθος μιας συμβολοσειράς,<br />

η charAt(int pos) που επιστρέφει τον χαρακτήρα που βρίσκεται στη θέση pos, η<br />

υπερφορτωμένη static μέθοδος valueOf(), η οποία δέχεται ως όρισμα μια<br />

αριθμητική τιμή και επιστρέφει την αναπαράστασή της ως συμβολοσειρά:<br />

//Επιστρέφει την συμβολοσειρά “123”<br />

String value = String.valueOf(123);<br />

Σημειώστε ότι τα αντικείμενα String είναι «αμετάβλητα» (immutable), με την<br />

έννοια ότι κάθε συμβολοσειρά απεικονίζεται ως ένα αντικείμενο που δεν μπορεί να<br />

αλλάξει, παρά μόνο με τη δημιουργία ενός νέου αντικειμένου. Κατά συνέπεια, ο<br />

έλεγχος ισότητας συμβολοσειρών με χρήση του τελεστή ισότητας == αποτιμάται<br />

πάντα ως false καθώς δυο αντικείμενα της κλάσης String αποτελούν διαφορετικά,<br />

αμετάβλητα αντικείμενα, ακόμη και αν αναπαριστάνουν την ίδια συμβολοσειρά.<br />

Για το λόγο αυτό, η σύγκριση δυο συμβολοσειρών γίνεται με χρήση της μεθόδου<br />

equals(Object anObject), η οποία επιστρέφει true αν το όρισμα anObject<br />

αναπαριστά την ίδια συμβολοσειρά με το String που καλεί τη μέθοδο:<br />

String anotherIsland = ”Ios”;<br />

if (iosIsland.equals(anotherIsland)) {<br />

//Αυτό είναι αληθές…<br />

}<br />

if (iosIsland == anotherIsland) {<br />

//Αυτό αποκλείεται…<br />

}<br />

Ο τελεστής + συνενώνει δυο συμβολοσειρές:<br />

String s = ”John ” + ”Doe”;<br />

//Το s έχει την τιμή “John Doe”<br />

Για το χειρισμό συμβολοσειρών η κλάση String διαθέτει ένα μεγάλο σύνολο<br />

μεθόδων. Η ηλεκτρονική τεκμηρίωση της Java παρέχει πληροφορίες για κάθε μια<br />

από αυτές τις μεθόδους.<br />

Κλάσεις και διαπροσωπείες συλλογών<br />

Στο πακέτο java.util της βασικής βιβλιοθήκης της Java παρέχονται κλάσεις για<br />

την υλοποίηση συχνά χρησιμοποιούμενων δομών δεδομένων που χρησιμοποιούνται<br />

σε πλήθος εφαρμογών. Οι ποιο ευρέως χρησιμοποιούμενες είναι οι<br />

κλάσεις Vector και HashMap, που παρουσιάζονται στη συνέχεια, οι οποίες<br />

χρησιμοποιούνται για την αποθήκευση και τον χειρισμό συλλογών από<br />

19


αντικείμενα. Σημειώνεται ότι οι κλάσεις αυτές είναι κατάλληλες για την υλοποίηση<br />

σχέσεων «ένα-προς-πολλά» μεταξύ κλάσεων, όπως θα φανεί στα παραδείγματα<br />

του σεμιναρίου.<br />

Vector<br />

Η κλάση Vector υλοποιεί έναν πίνακα του οποίου το μέγεθος είναι δυνατόν να<br />

μεταβάλλεται κατά την εκτέλεση του προγράμματος στον οποίον είναι δυνατόν να<br />

προστίθενται και να αφαιρούνται αντικείμενα. Η κλάση Vector, όπως και η<br />

HashMap, ανήκουν σε μια ειδική κατηγορία τύπων της Java που ονομάζονται<br />

γενικές (generics). Ένα generic δέχεται έναν ή περισσότερους τύπους (κλάσεις ή<br />

διαπροσωπείες) ως παραμέτρους:<br />

Vector names = new Vector();<br />

Στο παραπάνω τμήμα κώδικα ορίζεται το Vector names με παράμετρο τον τύπο<br />

String. Με αυτό τον τρόπο δηλώνεται ότι τα στοιχεία που προστίθενται στο<br />

συγκεκριμένο Vector πρέπει να είναι του τύπου που δηλώνεται ως παράμετρος.<br />

String name = ”Γεωργόπουλος”;<br />

names.add(name);<br />

Η εντολή for της Java έχει μια ειδική σύνταξη για την προσπέλαση των<br />

δεδομένων που περιέχονται σε συλλογές, όπως το Vector:<br />

for (String strName: names)<br />

{<br />

//Εκτύπωση του ονόματος στην κονσόλα<br />

System.out.println(strName);<br />

}<br />

Οι κλάσεις συλλογών πρέπει στην περίπτωση αυτή να υλοποιούν την διαπροσωπεία<br />

Iterable, η οποία υλοποιείται από την κλάση Vector. Αυτή η χρήση της<br />

for αντιστοιχεί στη χρήση της εντολής foreach άλλων γλωσσών προγραμματισμού<br />

για την προσπέλαση στοιχείων συλλογών.<br />

Η Vector περιέχει ένα σύνολο από μεθόδους για την εισαγωγή (add), διαγραφή<br />

(remove), αναζήτηση (contains) στοιχείων, κ.λπ.<br />

HashMap<br />

Η κλάση HashMap υλοποιεί έναν πίνακα αντιστοίχησης. Ένας τέτοιος πίνακας<br />

αντιστοιχίζει κλειδιά σε τιμές. Δεν επιτρέπονται διπλά κλειδιά, ενώ κάθε κλειδί<br />

αντιστοιχίζεται σε μια το πολύ τιμή. Μια τέτοια δομή επιτρέπει την αναζήτηση μιας<br />

συγκεκριμένης τιμής με βάση ένα μοναδικό κλειδί. Παράδειγμα ενός HashMap<br />

αποτελεί ένα λεξικό, όπου το λήμμα είναι το αποτελεί το κλειδί ενώ η ερμηνεία<br />

του, για παράδειγμα, η μετάφρασή του σε μια άλλη γλώσσα, αποτελεί την τιμή<br />

(value) στην οποία αντιστοιχίζεται το λήμμα.<br />

HashMap dictionary = new HashMap();<br />

dictionary.put(“boy”,”αγόρι”);<br />

dictionary.put(“cat”,”γάτα”);<br />

String catTrans = dictionary.get("cat");<br />

20


Η συμβολοσειρά catTrans του παραδείγματος παίρνει την τιμή “γάτα”, με την<br />

οποία έχει αντιστοιχηθεί στο λεξικό η συμβολοσειρά “cat”.<br />

Οι παραπάνω κλάσεις αποτελούν τμήμα μιας πλήρους αντικειμενοστρεφούς<br />

βιβλιοθήκης της Java που ονομάζεται Java Collection Framework. Η βιβλιοθήκη<br />

αυτή ορίζει μια ιεραρχία από διαπροσωπείες (interfaces) της Java που αντιστοιχούν<br />

σε διαφορετικές κατηγορίες συλλογών αντικειμένων καθώς και κλάσεις που<br />

υλοποιούν τις διαπροσωπείες αυτές. Οι διαπροσωπείες είναι οι ακόλουθες:<br />

Iterable<br />

Κλάσεις που υλοποιούν αυτή τη διαπροσωπεία επιτρέπουν στα αντικείμενά τους να<br />

χρησιμοποιούνται στην εντολή foreach.<br />

Collection<br />

Μια μη ταξινομημένη συλλογή από αντικείμενα όπου επιτρέπονται διπλές<br />

καταχωρήσεις. Η κλάση Vector, που παρουσιάστηκε προηγουμένως, υλοποιεί την<br />

διαπροσωπεία αυτή.<br />

Set<br />

Μη ταξινομημένη συλλογή όπου δεν επιτρέπονται διπλές καταχωρήσεις.<br />

List<br />

Ταξινομημένη συλλογή αντικειμένων όπου επιτρέπονται διπλές καταχωρήσεις.<br />

Ονομάζεται και ακολουθία. Η διαπροσωπεία List όσο και η Set κληρονομούν από<br />

την Collection, όπως φαίνεται στην Εικόνα 1. Η κλάση Vector που περιγράφηκε<br />

προηγουμένως υλοποιεί τη διαπροσωπεία List και την Collection.<br />

SortedList<br />

Μια ταξινομημένη ακολουθία στοιχείων όπου δεν επιτρέπονται διπλότυπα.<br />

Map<br />

Πίνακας αντιστοίχησης, με τα χαρακτηριστικά που περιγράφονται παραπάνω. Η<br />

κλάση HashMap που περιγράφηκε παραπάνω υλοποιεί τη διαπροσωπεία Map.<br />

SortedMap<br />

Ταξινομημένος πίνακας αντιστοίχησης. Κληρονομεί από τη διαπροσωπεία Map.<br />

<br />

Iterable<br />

<br />

Iterable<br />

<br />

Map<br />

<br />

Set<br />

<br />

List<br />

<br />

SortedMap<br />

HashMap<br />

<br />

SortedSet<br />

Vector<br />

Εικόνα 1: Κλάσεις και διαπροσωπείες συλλογών<br />

21


Ενότητα 3η:<br />

Μεθοδολογία Ανάπτυξης<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να γνωρίζουν μια απλή μεθοδολογία για την ανάλυση και σχεδίαση λογισμικού.<br />

Μεθοδολογία<br />

Στη συνέχεια παρουσιάζεται μια απλή μεθοδολογία για την ανάπτυξη<br />

προγραμμάτων στο πλαίσιο του σεμιναρίου. Συγκεντρώνει κοινά στοιχεία από τις<br />

περισσότερες υπάρχουσες πραγματικές αντικειμενοστρεφείς μεθόδους ανάπτυξης<br />

λογισμικού, χωρίς όμως την έκταση και τον φορμαλισμό κάθε μιας από αυτές. Η<br />

μεθοδολογία αυτή μπορεί να χρησιμοποιηθεί για την εύρεση των κλάσεων της<br />

ανάλυσης και τη σχεδίαση των εφαρμογών που αφορούν στις δραστηριότητες του<br />

σεμιναρίου.<br />

Αντικειμενοστρεφής ανάλυση<br />

Η ανάπτυξη λογισμικού περιλαμβάνει συνήθως τις παρακάτω θεμελιώδεις φάσεις:<br />

Ανάλυση, Σχεδίαση, Κωδικοποίηση, Έλεγχος. Η Ανάλυση αναφέρεται σε δύο<br />

βασικές εργασίες:<br />

• την κατανόηση του προβλήματος που επιλύει το λογισμικό που<br />

αναπτύσσεται μέσω της αποσαφήνισης των βασικών εννοιών, οντοτήτων<br />

και δεδομένων που αναφέρονται στο πεδίο εφαρμογής (domain) του<br />

προβλήματος.<br />

• τον καθορισμό των απαιτήσεων από το λογισμικό που πρόκειται να<br />

αναπτυχθεί, με άλλα λόγια, ποιες αναμένεται να είναι οι λειτουργίες και οι<br />

ιδιότητες του λογισμικού που αναπτύσσεται.<br />

Η κατανόηση του προβλήματος, γίνεται δημιουργώντας μια αφαίρεση, ένα μοντέλο<br />

που ονομάζεται Μοντέλο Πεδίου Εφαρμογής (Domain Model) ή Εννοιολογικό<br />

Μοντέλο (Conceptual model). Το εννοιολογικό μοντέλο αποτυπώνεται ως ένα<br />

σύνολο από κλάσεις, καθώς και από σχέσεις μεταξύ των κλάσεων αυτών. Οι<br />

κλάσεις αυτές ονομάζονται κλάσεις της ανάλυσης.<br />

Εύρεση κλάσεων της ανάλυσης<br />

Κατά την αντικειμενοστρεφή ανάλυση αποσαφηνίζονται βασικές οντότητες που<br />

αφορούν στην εφαρμογή με τη μορφή αρχικών κλάσεων, ή κλάσεων της<br />

ανάλυσης (analysis classes). Ανάλογα με τη φύση και το πεδίο εφαρμογής του<br />

προβλήματος, οι οντότητες αυτές αφορούν σε πράγματα π.χ. ένα προϊόν που<br />

πωλείται σε ένα κατάστημα, πρόσωπα π.χ. τα στοιχεία των μαθητών ενός<br />

σχολείου, γεγονότα, π.χ. η έγκριση ενός δανείου μιας τράπεζας, λειτουργίες, π.χ.<br />

ένας διαχειριστής των τραπεζικών λογαριασμών μιας τράπεζας. Η εύρεση των<br />

αρχικών κλάσεων είναι δυνατό να προκύψει από την περιγραφή του προβλήματος,<br />

ή του επιθυμητού συστήματος για το οποίο πρόκειται να αναπτυχθεί το λογισμικό.<br />

Η περιγραφή αυτή προκύπτει από συζητήσεις/ συνεντεύξεις με τους χρήστες του<br />

λογισμικού, από κείμενα, σχέδια, διαγράμματα, τεχνική τεκμηρίωση, κ.λπ. Ένας<br />

σχετικά απλός τρόπος για την εύρεση κλάσεων από μια τέτοια περιγραφή είναι η<br />

μέθοδος ουσιαστικών/ ρημάτων. Τα ουσιαστικά περιγράφουν «πράγματα» τα οποία<br />

είναι δυνατόν να αποτελέσουν κλάσεις αντικειμένων ενώ τα ρήματα περιγράφουν<br />

«δράσεις» οι οποίες είναι δυνατόν να αποτελέσουν μεθόδους των κλάσεων που<br />

αντιστοιχούν στα ονόματα στα οποία αναφέρονται τα ρήματα. Πρέπει να σημειωθεί<br />

ότι η μέθοδος αυτή δεν είναι ακριβής, αλλά επιτρέπει μια πρώτη προσέγγιση στην<br />

εύρεση κλάσεων. Επιπλέον κλάσεις είναι δυνατόν να προκύψουν, ενώ μερικά<br />

ρήματα δεν αποτελούν μεθόδους. Τέτοια ρήματα είναι τα «έχει», «περιλαμβάνει»,<br />

22


υποδεικνύουν σχέσεις μεταξύ κλάσεων και όχι μεθόδους. Τέλος, ανάλογα με τα<br />

συμφραζόμενα, μερικά ουσιαστικά είναι δυνατόν να αποτελέσουν ιδιότητες (πεδία)<br />

κλάσεων, και όχι κλάσεις. Δεν είναι απαραίτητη η λεπτομερής προδιαγραφή των<br />

πεδίων και των μεθόδων των κλάσεων κατά τη φάση αυτή, καθώς αυτή θα γίνει<br />

αργότερα κατά τη φάση της σχεδίασης. Οι κλάσεις της ανάλυσης περιγράφονται<br />

με διάφορους τρόπους. Οι ποιο συνηθισμένοι είναι η γλώσσα μοντελοποίησης UML,<br />

οι κάρτες CRC, καθώς και η χρήση κειμένου, όπως γίνεται στο σεμινάριο αυτό.<br />

Περιγραφή σεναρίων<br />

Ένα σενάριο καθορίζει μια λειτουργία του υπό ανάπτυξη λογισμικού<br />

περιγράφοντας μια σειρά από βήματα που συμβαίνουν κατά την αλληλεπίδραση<br />

ανάμεσα στο λογισμικό και σε έναν χρήστη του. Τα σενάρια αναφέρονται στην<br />

αντικειμενοστρεφή τεχνολογία και ως Περιπτώσεις Χρήσης (Use Cases) ή Ιστορίες<br />

(Stories). Η σημασία των σεναρίων, πέρα από το ότι αποτυπώνουν τις λειτουργικές<br />

απαιτήσεις από το λογισμικό βρίσκεται ότι αποτελούν τη βάση για την αντικειμενοστρεφή<br />

ανάπτυξη σε όλες τις φάσεις, σχεδίαση, υλοποίηση και έλεγχο, όπως θα<br />

φανεί στη συνέχεια.<br />

Σχεδίαση<br />

Η φάση της σχεδίασης ακολουθεί τη φάση της ανάλυσης. Σκοπός της σχεδίασης<br />

είναι ο ορισμός των κλάσεων και των πακέτων ενός προγράμματος σε τέτοιο<br />

βαθμό λεπτομέρειας ώστε να είναι δυνατή η υλοποίησή τους στην γλώσσα<br />

προγραμματισμού. Οι κλάσεις και τα πακέτα της σχεδίασης απεικονίζονται, με<br />

αντιστοιχία ένα προς ένα, σε πακέτα και κλάσεις κώδικα. Ενώ οι κλάσεις της<br />

ανάλυσης περιγράφουν τις οντότητες του πεδίου εφαρμογής, οι κλάσεις της<br />

σχεδίασης περιγράφουν τα πραγματικά αντικείμενα του λογισμικού. Μια πρώτη<br />

προσέγγιση των κλάσεων της σχεδίασης προκύπτει από τις κλάσεις της ανάλυσης.<br />

Για κάθε αρχική κλάση που προέκυψε κατά την ανάλυση, ορίζεται μια κλάση<br />

σχεδίασης. Κατά τη σχεδίαση προκύπτουν συνήθως περισσότερες κλάσεις από<br />

αυτές που προέκυψαν στην ανάλυση και επιπλέον ο βαθμός λεπτομέρειας στην<br />

περιγραφή των κλάσεων είναι πολύ μεγαλύτερος, καθώς πρέπει να περιγραφούν<br />

με λεπτομέρεια οι μέθοδοι και τα πεδία τους. Σε κάποιες περιπτώσεις, μια κλάση<br />

της ανάλυσης είναι δυνατόν να μην αντιστοιχηθεί σε μια κλάση σχεδίασης, αλλά,<br />

για παράδειγμα, σε ένα μόνο πεδίο μιας άλλης κλάσης για λόγους απλότητας ή<br />

επίδοσης του προγράμματος.<br />

Κωδικοποίηση<br />

Η κωδικοποίηση πραγματοποιείται με βάση το σχέδιο του λογισμικού που<br />

προέκυψε κατά τη σχεδίαση. Η κωδικοποίηση είναι δυνατόν να πραγματοποιείται<br />

παράλληλα από διαφορετικά μέλη της ομάδας ανάπτυξης. Στη συνέχεια<br />

πραγματοποιείται η συνένωση (integration) των επιμέρους μονάδων.<br />

Έλεγχος<br />

Έλεγχος είναι η διαδικασία της εκτέλεσης ενός προγράμματος, ή μονάδας<br />

προγράμματος, παρέχοντας ως είσοδο ένα σύνολο από δοκιμαστικά δεδομένα (test<br />

data) και συγκρίνοντας τα πραγματικά αποτελέσματα της εκτέλεσης με τα<br />

αναμενόμενα αποτελέσματα. Σκοπός του ελέγχου είναι η αποκάλυψη σφαλμάτων<br />

στο πρόγραμμα. Η μη εύρεση σφαλμάτων ενισχύει την πεποίθηση για την ορθή<br />

λειτουργία του προγράμματος αλλά δεν αποδεικνύει την ορθότητα της λειτουργίας<br />

του. Τρία είναι τα επίπεδα (ή οι φάσεις) του ελέγχου:<br />

• Έλεγχος μονάδας (unit testing) όπου ελέγχεται μια κλάση ή μια μέθοδος<br />

του προγράμματος<br />

• Έλεγχος ολοκλήρωσης (integration testing) όπου ελέγχεται το πρόγραμμα<br />

μετά τη συνένωση μονάδων του προγράμματος<br />

23


• Έλεγχος συστήματος (system testing) όπου ελέγχεται ολόκληρο το<br />

σύστημα.<br />

Στις δραστηριότητες αυτού του σεμιναρίου, οι επιμορφούμενοι όταν αναλαμβάνουν<br />

τον προγραμματισμό του τμήματος ενός προγράμματος καλό είναι να<br />

εκτελούν τον έλεγχο μονάδας για αυτό το τμήμα και στη συνέχεια η ομάδα εκτελεί<br />

από κοινού τον έλεγχο ολοκλήρωσης και συστήματος για ολόκληρο το πρόγραμμα.<br />

24


Ενότητα 4η:<br />

Aνάλυση μιας αυθεντικής κατάστασης<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να αναγνωρίζουν τις οντότητες ενός συγκεκριμένου πεδίου εφαρμογής και<br />

τις σχέσεις τους.<br />

• Να ορίζουν κλάσεις ανάλυσης με βάση τις οντότητες του πεδίου εφαρμογής.<br />

• Να ορίζουν τα σενάρια μιας εφαρμογής.<br />

Ο επιμορφωτής κάνει μια εισαγωγή στη δραστηριότητα, αποσαφηνίζοντας τους<br />

διδακτικούς της στόχους και εξηγώντας το πρόβλημα. Δίνονται στους<br />

επιμορφούμενους γραπτές οδηγίες, στις οποίες αναλύεται ο ρόλος του κάθε<br />

επιμορφούμενου καθώς και ο γενικότερος σκοπός της δραστηριότητας.<br />

Στους επιμορφούμενους παρουσιάζεται μια αυθεντική κατάσταση από τον<br />

πραγματικό κόσμο με πρόσωπα που επιτελούν λειτουργίες και αλληλεπιδρούν<br />

μεταξύ τους..<br />

Οι επιμορφούμενοι καλούνται να εντοπίσουν τις οντότητες (κλάσεις) που<br />

υπάρχουν σε μια αυθεντική κατάσταση η οποία αφορά σε μια αγορά προϊόντων, να<br />

τις αναλύσουν ως προς τις ιδιότητες που τις χαρακτηρίζουν μέσα στο συγκεκριμένο<br />

αυθεντικό παράδειγμα, ως προς τις λειτουργίες που επιτελούν.<br />

Στις επόμενες ενότητες που επίσης αφορούν στο παράδειγμα της αγοράς<br />

προϊόντων, οι επιμορφούμενοι σχεδιάζουν το μοντέλο κλάσεων αντικειμένων στο<br />

προγραμματιστικό περιβάλλον BlueJ, με την υποστήριξη του εκπαιδευτή.<br />

Έχοντας λάβει υπόψη το αυθεντικό παράδειγμα, οι λειτουργίες που<br />

επιτελούνται από τα αντικείμενα πρέπει να ανάγονται σε απλές μαθηματικές<br />

πράξεις και οι επιμορφούμενοι να συμπληρώνουν τη λειτουργικότητα των κλάσεων<br />

(κώδικας των μεθόδων τους) στο περιβάλλον BlueJ με απλές εντολές πρόσθεσης,<br />

αφαίρεσης, πολλαπλασιασμού με την βοήθεια του εκπαιδευτή.<br />

Στη συνέχεια ο επιμορφωτής παρουσιάζει πώς μπορούν οι επιμορφούμενοι<br />

στο περιβάλλον BlueJ, να δημιουργήσουν αντικείμενα από τις κλάσεις τις οποίες<br />

σχεδίασαν και των οποίων τη λειτουργικότητα όρισαν μέσω μεθόδων και πώς<br />

μπορούν να παράγουν αλληλεπιδράσεις μεταξύ των αντικειμένων ώστε να<br />

υλοποιηθεί η λειτουργικότητα του προγράμματος που προσομοιώνει την αυθεντική<br />

κατάσταση του παραδείγματος.<br />

Μετά από αυτό, οι επιμορφούμενοι καλούνται να εκτελέσουν τα σενάρια του<br />

αυθεντικού παραδείγματος που προέκυψαν στην αφηγηματική περιγραφή.<br />

Στη διαδικασία εκτέλεσης της δραστηριοτητας, αναδύεται η ανάγκη<br />

αναφοράς σε έννοιες, όπως κατασκευαστής, κελυφοποίηση, αφηρημένες κλάσειςμέθοδοι,<br />

κληρονομικότητα, πολυμορφισμός οι οποίες έχουν παρουσιαστεί σε<br />

προηγούμενες ενότητες.<br />

Ο επιμορφωτής και οι επιμορφούμενοι έχουν συγκεκριμένους ρόλους:<br />

Ρόλοι επιμορφούμενων<br />

Οι επιμορφούμενοι οργανώνονται σε ομάδες των τριών. Η ανάλυση και σχεδίαση<br />

και υλοποίηση γίνεται από κοινού από όλη την ομάδα.<br />

Ανάγνωση αφηγηματικής περιγραφής<br />

Πρόκειται για δραστηριότητα που αφορά στην σχεδίαση και την υλοποίηση ενός<br />

προγράμματος σε Java το οποίο αποτελεί μια αντικειμενοστρεφή προσομοίωση<br />

μιας αυθεντικής κατάστασης η οποία αφορά σε μια αγορά προϊόντων. Η αυθεντική<br />

25


αυτή κατάσταση παρουσιάζεται στους επιμορφούμενους μέσω μιας γραπτής<br />

περιγραφής. Η περιγραφή αυτή δίνεται στη συνέχεια:<br />

Σε μια αγορά κινούνται οι αγοραστές και υπάρχουν οι πωλητές με τα<br />

προϊόντα τους. Οι αγοραστές έχουν ένα καλάθι στο οποίο τοποθετούν τα προϊόντα<br />

που αγοράζουν και το πορτοφόλι από το οποίο πληρώνουν ό,τι αγοράσουν.<br />

Αντίστοιχα οι πωλητές έχουν το «ταμείο» τους με τα χρήματα που εισπράττουν<br />

από τις πωλήσεις.<br />

Οι αγοραστές διαλέγουν προϊόντα, τα οποία ζυγίζονται, υπολογίζεται η αξία<br />

τους, πληρώνουν το ποσό στον πωλητή ο οποίος το εισπράττει και το βάζει στο<br />

«ταμείο» του και τοποθετούν τα προϊόντα που αγόρασαν στο καλάθι τους.<br />

Τα προϊόντα που υπάρχουν στην αγορά είναι δύο κατηγοριών: τα πρώτης<br />

ποιότητας, τα οποία πωλούνται στην κανονική τους τιμή, και τα δεύτερης<br />

ποιότητας, τα οποία πωλούνται με έκπτωση.<br />

Αρχικός εντοπισμός οντοτήτων<br />

Οι επιμορφούμενοι αναγνωρίζουν στο αυθεντικό παράδειγμα όλες τις οντότητες,<br />

χρησιμοποιώντας τη μεθοδολογία που παρουσιάστηκε στην προηγούμενη ενότητα.<br />

Οδηγίες προς τους επιμορφούμενους<br />

Κάντε μια λίστα των βασικών οντοτήτων που παρατηρείτε στην αυθεντική<br />

κατάσταση.<br />

Προσδοκώμενο αποτέλεσμα<br />

Οι οντότητες που προκύπτουν μετά από αυτή τη δραστηριότητα, οι οποίες<br />

αποτελούν τις κλάσεις της ανάλυσης, είναι:<br />

• Αγοραστής (Customer)<br />

• Προϊόν (Product)<br />

• Προϊόν Πρώτης Ποιότητας (FirstClassProduct)<br />

• Προϊόν Δεύτερης Ποιότητας (SecondClassProduct)<br />

• Καλάθι (Basket)<br />

• Πωλητής (Seller)<br />

Περιγραφή των οντοτήτων<br />

Οι επιμορφούμενοι συζητούν τις οντότητες που εντόπισαν στην προηγούμενη<br />

δραστηριότητα, προσδιορίζοντας τα χαρακτηριστικά και τις λειτουργίες κάθεμιας<br />

από αυτές.<br />

Περιγραφή σεναρίων<br />

Τα σενάρια που προκύπτουν είναι:<br />

• Ζύγιση προϊόντος<br />

• Υπολογισμός αξίας προϊόντος<br />

• Πληρωμή ποσού<br />

• Είσπραξη ποσού<br />

• Τοποθέτηση του προϊόντος στο καλάθι κάποιου συγκεκριμένου αγοραστή.<br />

Οδηγίες προς τους επιμορφούμενους<br />

Περιγράψτε τις λειτουργίες που εκτελεί κάθε οντότητα. Προσπαθήστε να<br />

εντοπίσετε τις ουσιαστικές λειτουργίες που έχουν σχέση με την αυθεντική<br />

κατάσταση που ζητείται να προσομοιωθεί. Έτσι, η λειτουργία του αγοραστή<br />

«περπατάει στην αγορά» δεν ενδιαφέρει.<br />

Σκεφθείτε ποια χαρακτηριστικά, τα οποία έχουν σημασία για τη συγκεκριμένη<br />

αυθεντική κατάσταση, καθορίζουν την κατάσταση των οντοτήτων κάθε στιγμή.<br />

Σημειώστε ότι αποτέλεσμα αυτής της ανάλυσης είναι η εύρεση των<br />

26


χαρακτηριστικών μιας οντότητας αλλά και ο εντοπισμός σχέσεων μεταξύ<br />

οντοτήτων.<br />

Σκεφθείτε αν είναι δυνατόν να υπάρχουν περισσότεροι από ένας εκπρόσωποι μιας<br />

οντότητας, για παράδειγμα πολλά διαφορετικά προϊόντα.<br />

Επιβεβαιώστε ότι καλύπτονται όλες οι απαιτήσεις του προβλήματος που<br />

περιγράφηκε, από τις οντότητες (κλάσεις) και τις λειτουργίες τις οποίες τους<br />

αποδώσατε.<br />

Προσδοκώμενο αποτέλεσμα<br />

Το αποτέλεσμα αυτής της δραστηριότητας είναι μια λεκτική περιγραφή για κάθε<br />

οντότητα, όπως φαίνεται στη συνέχεια:<br />

• Ο αγοραστής έχει ένα καλάθι και ένα πορτοφόλι. Διαλέγει προϊόντα, τα<br />

ζυγίζει ο πωλητής, πληρώνει την αξία που θα υπολογίσει ο πωλητής και<br />

βάζει αυτό που αγόρασε στο καλάθι του. Ο αγοραστής ζητά εξυπηρέτηση<br />

από τον πωλητή.<br />

• Το προϊόν χαρακτηρίζεται από το όνομά του και την τιμή του.<br />

• Το προϊόν πρώτης ποιότητας χαρακτηρίζεται από το όνομά του και την<br />

τιμή του που είναι ίδια με την τιμή της οντότητας προϊόν.<br />

• Το προϊόν δεύτερης ποιότητας χαρακτηρίζεται από το όνομά του, το<br />

ποσοστό έκπτωσης στην τιμή του και την τιμή του που υπολογίζεται από<br />

την τιμή της οντότητας προϊόν και το ποσοστό έκπτωσης της τιμής του.<br />

• Το καλάθι έχει προϊόντα και τοποθετούνται σε αυτό τα προϊόντα που<br />

αγοράζονται.<br />

• Ο πωλητής έχει το ταμείο του, ζυγίζει τα προϊόντα, υπολογίζει την αξία<br />

τους και εισπράττει το ποσό της αξίας τους από τους αγοραστές το οποίο<br />

βάζει στο ταμείο του.<br />

27


Ενότητα 5η:<br />

Σχεδίαση κλάσεων στο BlueJ<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να δημιουργούν έργα στο BlueJ<br />

• Να δημιουργούν και να διαγράφουν κλάσεις στο BlueJ<br />

• Να δημιουργούν και να διαχειρίζονται αφηρημένες κλάσεις στο BlueJ<br />

• Να ορίζουν σχέσεις κληρονομικότητας μεταξύ κλάσεων στο ΒluleJ<br />

Οι οντότητες που εντοπίστηκαν στην προηγούμενη ενότητα πρόκειται να<br />

αποτυπωθούν σε ένα σχέδιο ενός προγράμματος με τη χρήση του περιβάλλοντος<br />

BlueJ ως κλάσεις.<br />

Για την έναρξη του προγράμματος BlueJ εκτελέστε το πρόγραμμα bluej.exe το<br />

οποίο βρίσκεται στον κατάλογο εγκατάστασης του BlueJ.<br />

Η δημιουργία ενός έργου στο BlueJ παρουσιάζεται στην επόμενη παράγραφο.<br />

Δημιουργία έργου στο BlueJ<br />

Επιλέξτε ‘Project -> New Project’ από το μενού του BlueJ.<br />

Στο πλαίσιο διαλόγου που εμφανίζεται δώστε το όνομα του έργου, στην<br />

προκειμένη περίπτωση market και κάντε κλικ στο κουμπί Create.<br />

Εικόνα 2. Δημιουργία έργου στο BlueJ<br />

Δημιουργία και διαγραφή κλάσεων στο BlueJ<br />

Δημιουργήστε στο BlueJ μια κλάση για κάθε οντότητα του προβλήματος, όπως<br />

αυτή ορίστηκε στο προηγούμενο βήμα. Η δημιουργία μιας κλάσης γίνεται κάνοντας<br />

κλικ στο κουμπί ‘New Class…’ αριστερά στην επιφάνεια εργασίας του BlueJ.<br />

Εμφανίζεται ένα πλαίσιο διαλόγου, όπως φαίνεται στην Εικόνα 3, στο οποίο<br />

εισάγετε το όνομα της κλάσης.<br />

28


Εικόνα 3. Δημιουργία κλάσης στο BlueJ<br />

Στην Εικόνα 3 παρουσιάζεται η δημιουργία της κλάσης Customer. Μετά την<br />

εισαγωγή της η κλάση εμφανίζεται στην κεντρική περιοχή της επιφάνειας του<br />

BlueJ η οποία περιέχει το διάγραμμα κλάσεων, όπως φαίνεται στην Εικόνα 4.<br />

Κατά τη διαδικασία της σχεδίασης είναι πιθανό να χρειαστεί να διαγράψετε κάποια<br />

κλάση. Για τη διαγραφή μιας κλάσης κάντε δεξί κλικ στο εικονίδιο της κλάσης στο<br />

διάγραμμα κλάσεων και στη συνέχεια στο πτυσσόμενο (pop-up) μενού που<br />

εμφανίζεται επιλέξτε “Remove”.<br />

Εικόνα 4. Κλάση στο BlueJ<br />

Δημιουργία αφηρημένων κλάσεων<br />

Για τη δημιουργία αφηρημένης κλάσης κάντε κλικ στο κουμπί “New Class…” και<br />

στη συνέχεια επιλέξτε τον τύπο “Abstract class” όπως φαίνεται στην Εικόνα 5.<br />

29


Εικόνα 5. Εισαγωγή αφηρημένης κλάσης<br />

Η αφηρημένη κλάση Product εμφανίζεται στο διάγραμμα κλάσεων με τον<br />

προσδιοριστή , όπως φαίνεται στην Εικόνα 6.<br />

Εικόνα 6. Εμφάνιση αφηρημένης κλάσης<br />

Ορισμός σχέσεων κληρονομικότητας<br />

Οι κλάσεις FirstQualityProduct και SecondQualityProduct είναι υποκλάσεις<br />

της Product, δηλαδή κληρονομούν από αυτή. Για τον ορισμό σχέσεων<br />

κληρονομικότητας κάντε κλικ στο κουμπί με το βέλος της κληρονομικότητας (η<br />

συνεχής γραμμή με το τρίγωνο στο άκρο) και συνδέστε τις κλάσεις με τέτοιο<br />

τρόπο ώστε το τρίγωνο να βρίσκεται στην άκρη, να πρόσκειται στην κλάση η οποία<br />

κληρονομείται, όπως φαίνεται στην Εικόνα 7.<br />

30


Εικόνα 7. Σχέση κληρονομικότητας στο διάγραμμα κλάσεων<br />

31


Ενότητα 6η:<br />

Εύρεση ιδιοτήτων και λειτουργιών των κλάσεων<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να εντοπίζουν τις ιδιότητες των κλάσεων που σχεδιάζουν.<br />

• Να εντοπίζουν τις λειτουργίες των κλάσεων που σχεδιάζουν.<br />

Αποφασίστε για τις ιδιότητες και λειτουργίες των οντοτήτων που έχετε εντοπίσει<br />

στις προηγούμενες ενότητες. Αυτές οι ιδιότητες και λειτουργίες θα αποτυπωθούν<br />

ως πεδία και μέθοδοι, αντίστοιχα, των κλάσεων που έχετε δημιουργήσει.<br />

Προσδοκώμενο Αποτέλεσμα<br />

Οντότητα (κλάση) Αγοραστής (Customer)<br />

Ιδιότητες (πεδία)<br />

• καλάθι του τύπου Καλάθι (Basket)<br />

• ποσό στο πορτοφόλι του τύπου πραγματικός αριθμός<br />

Λειτουργίες (μέθοδοι)<br />

Πληρώνει την αξία ενός προϊόντος που θα υπολογίσει ο πωλητής. Η αξία είναι<br />

δεδομένο ποσό (amount) το οποίο αφαιρείται από το πορτοφόλι του αγοραστή.<br />

Υπογραφή της μεθόδου: void pay (double amount)<br />

Οντότητα Προϊόν (Product)<br />

Ιδιότητες<br />

• όνομα του τύπου σειρά χαρακτήρων<br />

• τιμή του τύπου πραγματικός αριθμός<br />

Οντότητα Προϊόν Πρώτης Ποιότητας (FirstQualityProduct)<br />

Ιδιότητες<br />

• όνομα του τύπου σειρά χαρακτήρων<br />

• τιμή του τύπου πραγματικός αριθμός<br />

Οντότητα Προϊόν Δεύτερης Ποιότητας (SecondQualityProduct)<br />

Ιδιότητες<br />

• όνομα του τύπου σειρά χαρακτήρων<br />

• τιμή του τύπου πραγματικός αριθμός<br />

• ποσοστό έκπτωσης στην τιμή του τύπου πραγματικός αριθμός<br />

Λειτουργίες (μέθοδοι)<br />

Υπολογισμός της τιμής πώλησης του προϊόντος. Η επιστρεφόμενη τιμή<br />

υπολογίζεται με βάση την τιμή του προϊόντος και την έκπτωση σύμφωνα με τον<br />

τύπο:<br />

= * (1 – ( / 100))<br />

Υπογραφή μεθόδου: double salePrice()<br />

Οντότητα Καλάθι (Basket)<br />

Ιδιότητες<br />

• προϊόντα του τύπου Προϊόν (πίνακας της κλάσης java.util.Vector με<br />

στοιχεία του τύπου προϊόν)<br />

Λειτουργίες (μέθοδοι)<br />

32


Τοποθέτηση ενός συγκεκριμένου προϊόντος στο καλάθι. Χρειάζεται να<br />

προσδιοριστεί το προϊόν το οποίο αγοράστηκε και η καθαυτό λειτουργία είναι να<br />

προστεθεί στον πίνακα το προϊόν αυτό.<br />

Υπογραφή μεθόδου: void addProduct(Product aProduct)<br />

Οντότητα Πωλητής (Seller)<br />

Ιδιότητες<br />

• ποσό στο ταμείο του τύπου πραγματικός αριθμός<br />

Λειτουργίες (μέθοδοι)<br />

Ζυγίζει τα προϊόντα. Από τη λειτουργία αυτή εξάγεται (επιστρέφεται) το βάρος του<br />

προϊόντος, τύπου πραγματικού αριθμού διπλής ακρίβειας (double).<br />

Υπογραφή μεθόδου: double weigh(Product aProduct)<br />

Υπολογίζει την αξία των προϊόντων που αγοράζουν οι πελάτες. Χρειάζεται να<br />

προσδιοριστεί το προϊόν το οποίο αγοράστηκε και η ποσότητα του. Η καθαυτό<br />

λειτουργία είναι να πολλαπλασιαστεί η τιμή του προϊόντος, η οποία θα αποκτηθεί<br />

με προσπέλαση στην οντότητα προϊόν, επί την ποσότητα και να επιστραφεί το<br />

αποτέλεσμα.<br />

Υπογραφή μεθόδου: double calculateValue(Product aProduct, double<br />

quantity)<br />

Εισπράττει χρήματα από τους αγοραστές. Χρειάζεται να προσδιοριστεί το ποσόν και<br />

η καθαυτό λειτουργία είναι να προστεθεί το ποσό στο «ταμείο» του πωλητή.<br />

Υπογραφή μεθόδου: void receivePayment(double amount)<br />

33


Ενότητα 7η:<br />

Συγγραφή κώδικα κλάσεων και δημιουργία αντικειμένων<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να χρησιμοποιούν το διορθωτή κλάσεων του BlueJ για να διορθώνουν τον<br />

κώδικα μιας κλάσης.<br />

• Να ορίζουν πεδία κλάσεων.<br />

• Να ορίζουν μεθόδους κλάσεων.<br />

• Να ορίζουν μεθόδους κατασκευαστών κλάσεων.<br />

• Να μεταγλωττίζουν μεμονωμένες κλάσεις.<br />

• Να μεταγλωττίζουν όλες τις κλάσεις ενός έργου.<br />

• Να εντοπίζουν και να διορθώνουν σφάλματα μεταγλώττισης με το διορθωτή<br />

του BlueJ.<br />

• Να δημιουργούν αντικείμενα.<br />

• Να εκτελούν μεθόδους αντικειμένων.<br />

• Να επιθεωρούν την κατάσταση αντικειμένων<br />

• Να κατανοούν τη χρήση αφηρημένων κλάσεων και μεθόδων.<br />

Για τον ορισμό των πεδίων (fields) και των μεθόδων μιας κλάσης στο BlueJ<br />

είναι απαραίτητη η διόρθωση του πηγαίου κώδικα της κλάσης. Ο τρόπος με τον<br />

οποίο πραγματοποιείται η διόρθωση περιγράφεται στη συνέχεια.<br />

Διόρθωση του κώδικα μιας κλάσης<br />

Κατά τον ορισμό μιας κλάσης με το BlueJ δημιουργείται αυτόματα πηγαίος κώδικας<br />

για την κλάση. Για την πρόσβαση σε αυτόν τον κώδικα, κάντε διπλό κλικ πάνω στο<br />

εικονίδιο της κλάσης στο διάγραμμα κλάσεων. Εμφανίζεται τότε το παράθυρο του<br />

διορθωτή κώδικα (Editor) με τον κώδικα της κλάσης, όπως φαίνεται στην Εικόνα<br />

8. Με τη χρήση του διορθωτή είναι δυνατή η ανάγνωση και διόρθωση του κώδικα<br />

των κλάσεων του BlueJ. Το BlueJ υποστηρίζει πλήρως τη γλώσσα Java. Με τη<br />

δημιουργία μιας κλάσης δημιουργείται αυτόματα κώδικας που αφορά στη δήλωση<br />

και το χειρισμό ενός πεδίου τύπου ακέραιου, όπως φαίνεται στη συνέχεια:<br />

private int x;<br />

Ο κώδικας αυτός είναι ενδεικτικός και πρέπει να διαγραφεί. Διαγράψτε την<br />

παραπάνω δήλωση (γραμμή 11 στον αρχικό κώδικα της κλάσης), την εντολή<br />

ανάθεσης<br />

x = 0;<br />

στην γραμμή 19 του αρχικού κώδικα της κλάσης και τον ορισμό της μεθόδου<br />

sampleMethod (γραμμές 22 έως 32). Για την εμφάνιση ή απόκρυψη των<br />

γραμμών κώδικα στο διορθωτή επιλέξτε “Options->Preferences” από το μενού του<br />

διορθωτή και στη συνέχεια επιλέξτε κάνοντας κλικ στην επιλογή “Display line<br />

numbers”.<br />

34


Εικόνα 8. Διορθωτής κώδικα<br />

Διορθώστε τον κώδικα μιας κλάσης ορίζοντας πεδία και μεθόδους στη γλώσσα<br />

Java.<br />

Εικόνα 9. Εμφάνιση αρίθμησης γραμμών στο διορθωτή κώδικα<br />

Ο κώδικας κάθε κλάσης διορθώνεται ξεχωριστά, όπως φαίνεται στην Εικόνα 8.<br />

Μετά την ενημέρωση του κώδικα μιας κλάσης με χρήση του διορθωτή κώδικα,<br />

ενδέχεται να εμφανιστούν σχέσεις εξάρτησης ("Uses”) μεταξύ κλάσεων στο<br />

διάγραμμα κλάσεων. Εξάρτηση μεταξύ δυο κλάσεων υπάρχει όταν μια κλάση<br />

χρησιμοποιεί κώδικα μιας άλλης κλάσης. Μια σχέση εξάρτησης παριστάνεται στο<br />

35


διάγραμμα κλάσεων με μια διακεκομμένη γραμμή που συνδέει δύο κλάσεις με ένα<br />

βέλος στην άκρη της κλάσης από την οποία εξαρτάται προκύπτει η εξάρτηση.<br />

Παραδείγματα σχέσεων εξάρτησης παρουσιάζονται στην Εικόνα 10. Στην ίδια<br />

εικόνα, η κλάση Customer έχει ένα πεδίο του τύπου Basket:<br />

private Basket myBasket;<br />

Έτσι, η κλάση Customer εμφανίζεται στην Εικόνα 10 να συνδέεται με μια<br />

σχέση εξάρτησης με την κλάση Basket.<br />

Εικόνα 10. Εμφάνιση σχέσεων εξάρτησης στο διάγραμμα κλάσεων<br />

Ας σημειωθεί ότι η σχέση εξάρτησης είναι δυνατόν να οριστεί και γραφικά, στο<br />

διάγραμμα κλάσεων, με τον ίδιο τρόπο με τη σχέση κληρονομικότητας, όπως<br />

παρουσιάστηκε προηγουμένως.<br />

Μεταγλώττιση<br />

Τη διόρθωση του κώδικα μιας ή περισσοτέρων κλάσεων ακολουθεί η μεταγλώττιση.<br />

Η μεταγλώττιση είναι δυνατόν να πραγματοποιηθεί είτε συνολικά, οπότε<br />

μεταγλωττίζονται όλες οι κλάσεις ενός έργου στο BlueJ, είτε χωριστά για κάθε<br />

κλάση.<br />

Για τη μεταγλώττιση ολόκληρου του έργου κάντε κλικ στο κουμπί ‘Compile’ δεξιά<br />

στην επιφάνεια εργασίας του BlueJ. Εάν υπάρχει σφάλμα μεταγλώττισης σε κάποια<br />

κλάση, το BlueJ εμφανίζει τον κώδικα αυτής της κλάσης με το διορθωτή κώδικα<br />

εμφανίζοντας κατάλληλο μήνυμα σφάλματος στη γραμμή κατάστασης (κάτω<br />

αριστερά) στο πλαίσιο του διορθωτή κώδικα. Επιπλέον, επισημαίνεται η θέση του<br />

πρώτου σφάλματος μεταγλώττισης που εντοπίστηκε καθώς και το κατάλληλο<br />

μήνυμα σφάλματος του μεταγλωττιστή στο κάτω μέρος του παραθύρου του<br />

διορθωτή κλάσεων, όπως φαίνεται στην Εικόνα 11.<br />

36


Η μεταγλώττιση μιας μεμονωμένης κλάσης γίνεται στο διάγραμμα κλάσεων<br />

κάνοντας κλικ με το δεξί πλήκτρο του ποντικού στην αντίστοιχη κλάση και<br />

επιλέγοντας ‘Compile’ στο πτυσσόμενο (pop-up) μενού που εμφανίζεται (Εικόνα<br />

12). Εναλλακτικά, ενώ διορθώνετε τον κώδικα της κλάσης στο διορθωτή κώδικα<br />

της κλάσης κάντε κλικ στο κουμπί Compile πάνω δεξιά στην οθόνη. Παρατηρήστε<br />

ότι μια κλάση που είτε δεν έχει μεταγλωττιστεί, είτε ο κώδικάς της έχει αλλάξει<br />

μετά την προηγούμενη μεταγλώττιση, παρουσιάζεται στο διάγραμμα κλάσεων<br />

διαγραμμισμένη, ενώ μετά τη μεταγλώττισή της η διαγράμμιση εξαφανίζεται. Έτσι,<br />

οι κλάσεις στην Εικόνα 7 εμφανίζονται διαγραμμισμένες, αντίθετα με τις<br />

μεταγλωττισμένες κλάσεις στην Εικόνα 10.<br />

Εικόνα 11. Μήνυμα σφάλματος κατά τη μεταγλώττιση<br />

37


Εικόνα 12. Μεταγλώττιση μεμονωμένης κλάσης<br />

Ορισμός πεδίων<br />

Όπως αναφέρθηκε, τα πεδία ή οι μεταβλητές-μέλη μιας κλάσης αποτυπώνουν την<br />

κατάσταση των αντικειμένων αυτής της κλάσης. Ο ορισμός πεδίων στο BlueJ<br />

γίνεται με χρήση του διορθωτή κώδικα. Παράδειγμα ορισμού πεδίων στη γλώσσα<br />

Java αποτελεί το παρακάτω:<br />

public class Customer<br />

{<br />

}<br />

private Basket myBasket;<br />

private double walletAmount;<br />

// . . .<br />

Στο παράδειγμα, το πεδίο myBasket της κλάσης Customer είναι τύπου Basket, ενώ<br />

το πεδίο walletAmount είναι τύπου double. Η ορατότητα και των δύο πεδίων<br />

ορίζεται ως private. Σημειώστε ότι η οντότητα (κλάση) «Πορτοφόλι» που<br />

προέκυψε από κατά ανάλυση εδώ υλοποιείται ως ένα πεδίο της κλάσης Customer,<br />

το πεδίο walletAmmount, καθώς δεν κρίνεται απαραίτητο για την σχεδίαση και την<br />

υλοποίηση να υπάρχει ξεχωριστή κλάση γι’ αυτήν.<br />

Η κλάση Basket συνδέεται με την κλάση Product με μια σχέση ένα-προς-πολλά.<br />

Με άλλα λόγια ένα καλάθι είναι δυνατόν να έχει πολλά προϊόντα. Μια τέτοια σχέση<br />

υλοποιείται με χρήση μιας κλάσης συλλογών όπως η java.util.Vector. Έτσι<br />

ορίζεται ένα πεδίο στην κλάση Basket ως εξής:<br />

class Basket<br />

{<br />

//…<br />

Collection myProducts;<br />

//…<br />

}<br />

Ορισμός μεθόδων<br />

38


Για την απόδοση λειτουργικότητας στις κλάσεις απαιτείται ο ορισμός μεθόδων οι<br />

οποίες υλοποιούν τις διάφορες λειτουργίες των κλάσεων, όπως αυτές<br />

προδιαγράφηκαν προηγουμένως. Ενδεικτικά, απαιτείται η υλοποίηση των μεθόδων<br />

addProduct, weigh, pay, receivePayment, calculateValue, salePrice, κ.λπ.<br />

Ιδιαίτερα η μέθοδος addProduct(Product aProduct) της κλάσης Basket για την<br />

προσθήκη ενός προϊόντος στο καλάθι ενός αγοραστή υλοποιείται με χρήση της<br />

μεθόδου add της κλάσης Vector ως εξής:<br />

public void addProduct(Product aProduct)<br />

{<br />

products.add(aProduct);<br />

}<br />

Επιπλέον, η μέθοδος weigh() προσομοιώνει τη λειτουργία της ζύγισης ενός<br />

προϊόντος με την παραγωγή τυχαίου πραγματικού αριθμού με τη χρήση της<br />

μεθόδου random της κλάσης java.lang.Math για την παραγωγή τυχαίων<br />

αριθμών.<br />

Ορισμός κατασκευαστών<br />

Πέρα από τη χρήση μεθόδων ανάγνωσης και ανάθεσης τιμής που αναφέρθηκαν<br />

παραπάνω, πρέπει να δημιουργηθούν αντικείμενα με συγκεκριμένες τιμές των<br />

πεδίων τους κατά την αρχικοποίηση (π.χ. ποσό στο πορτοφόλι του αγοραστή, τιμή<br />

προϊόντος). Για το σκοπό αυτό θα οριστούν οι αναγκαίοι μέθοδοι κατασκευαστές:<br />

(Basket, Costumer, FirstQualityProduct, SecondQualityProduct), με<br />

συγκεκριμένες παραμέτρους για την ανάθεση τιμών στα πεδία κάθε κλάσης. Για<br />

παράδειγμα, ο παρακάτω constructor αρχικοποιεί την κλάση<br />

FirstQualityProduct δίνοντας τιμές στα πεδία name και price της κλάσης.<br />

public FirstQualityProduct(String name, double price)<br />

{<br />

//...<br />

}<br />

Οι επιμορφούμενοι καλούνται να υλοποιήσουν τους κατασκευαστές των κλάσεων.<br />

Ιδιαίτερα, η κλάση Basket διαθέτει ως πεδίο, έναν πίνακα τύπου Vector από<br />

προϊόντα και έτσι απαιτείται η δημιουργία αντικειμένου τύπου Vector στην μέθοδο<br />

του κατασκευαστή<br />

myProducts = new java.util.Vector();<br />

Ορισμός μεθόδων ανάγνωσης και ανάθεσης τιμών<br />

Αποτελεί συνήθη πρακτική στον αντικειμενοστρεφή προγραμματισμό ορισμός των<br />

πεδίων μιας κλάσης με τον μετατροπέα ορατότητας private, όπως παρουσιάστηκε<br />

σε προηγούμενο παράδειγμα. Σε τέτοια πεδία έχουν πρόσβαση μόνο μέθοδοι<br />

που ανήκουν στην ίδια κλάση. Με αυτόν τον τρόπο αποκρύπτονται οι λεπτομέρειες<br />

της υλοποίησης μιας κλάσης και υποστηρίζεται έτσι ένα από τα βασικά<br />

χαρακτηριστικά του αντικειμενοστρεφούς προγραμματιστικού παραδείγματος που<br />

είναι η κελυφοποίηση (encapsulation) ή αλλιώς απόκρυψη πληροφοριών<br />

(information hiding). Έτσι, θα προκύψει η ανάγκη να οριστούν σε κάθε κλάση<br />

μέθοδοι για την ανάθεση αλλά και την ανάγνωση των τιμών στα πεδία της κλάσης.<br />

Για παράδειγμα, για να προσδιοριστεί ποιο είναι το καλάθι κάποιου αγοραστή<br />

ορίζεται μια μέθοδος ανάγνωσης της τιμής του πεδίου myBasket της κλάσης<br />

Customer. Ως παράδειγμα, η μέθοδος:<br />

public Basket getBasket()<br />

{<br />

return myBasket;<br />

39


}<br />

χρησιμοποιείται για την ανάγνωση της τιμής του πεδίου myBasket στην κλάση<br />

Customer. Το πεδίο myBasket έχει ορατότητα private και δεν είναι δυνατή με<br />

άλλο τρόπο η πρόσβαση στην τιμή του. Η μέθοδος getBasket δηλώνεται με<br />

ορατότητα public, ενώ η τιμή που επιστρέφει έχει τον ίδιο τύπο με το πεδίο<br />

myBasket. Το όνομα της μεθόδου έχει το πρόθεμα ‘get’. Παρ’ ότι αυτό δεν είναι<br />

υποχρεωτικό, αποτελεί μια σύμβαση που ακολουθείται ευρέως στη γλώσσα Java<br />

και την αντικειμενοστρεφή ανάπτυξη λογισμικού γενικότερα. Αντίστοιχα, η<br />

μέθοδος:<br />

public void setBasket(Basket basket)<br />

{<br />

this.myBasket = basket;<br />

}<br />

αναθέτει την τιμή του ορίσματός της στο πεδίο myBasket. Αντίστοιχα, το πρόθεμα<br />

‘set’ τίθεται στις μεθόδους απόδοσης τιμών σε πεδία κλάσεων.<br />

Δημιουργία αντικειμένων<br />

Για να είναι δυνατή η δημιουργία ενός αντικειμένου (instance) μιας κλάσης στο<br />

BlueJ είναι απαραίτητο η κλάση να έχει μεταγλωττιστεί επιτυχώς. Κατά τη<br />

συγγραφή του κώδικα μιας κλάσης γίνεται έλεγχος της λειτουργίας της<br />

μεταγλωττίζοντάς την και δημιουργώντας αντικείμενα της κλάσης ώστε να<br />

ελέγχεται η ορθότητά της.<br />

Για τη δημιουργία ενός αντικειμένου μιας κλάσης στο BlueJ κάντε κλικ με το δεξί<br />

πλήκτρο του ποντικιού στο εικονίδιο της κλάσης στο διάγραμμα κλάσεων και<br />

επιλέξτε έναν από τους κατασκευαστές (constructors) της κλάσης στο πτυσσόμενο<br />

(pop-up) μενού που εμφανίζεται, όπως φαίνεται στην Εικόνα 13. Η μέθοδος του<br />

κατασκευαστή είναι δυνατόν να περιέχει παραμέτρους. Σε αυτήν την περίπτωση η<br />

εισαγωγή των παραμέτρων γίνεται σε κατάλληλο πλαίσιο διαλόγου που εμφανίζεται,<br />

όπως περιγράφεται στη συνέχεια.<br />

40


Εικόνα 13. Δημιουργία αντικειμένου<br />

Στο πλαίσιο διαλόγου που εμφανίζεται πληκτρολογήστε το όνομα του αντικειμένου<br />

(instance), όπως φαίνεται στην Εικόνα 14.<br />

Εικόνα 14. Πλαίσιο δημιουργίας αντικειμένου<br />

Μετά την εκτέλεση του κατασκευαστή το αντικείμενο εμφανίζεται στον «πάγκο<br />

αντικειμένων» (object bench) στο κάτω αριστερό μέρος της οθόνης (Εικόνα 15).<br />

Για την αφαίρεση ενός αντικειμένου κάντε δεξί κλικ στο εικονίδιό του στον πάγκο<br />

αντικειμένων και επιλέξτε ‘Remove’ στο πτυσσόμενο μενού που εμφανίζεται.<br />

41


Εικόνα 15. Εμφάνιση αντικειμένου στον πάγκο αντικειμένων<br />

Κλήση μεθόδων και επιθεώρηση αντικειμένων<br />

Για να καλέστε μια μέθοδο μιας κλάσης πρέπει να έχετε αρχικά δημιουργήσει<br />

αντικείμενα της κλάσης αυτής. Εξαίρεση αποτελούν οι στατικές (static) μέθοδοι, οι<br />

οποίες εφαρμόζονται στην κλάση την ίδια και όχι σε κάποιο στιγμιότυπό της<br />

(αντικείμενο). Όπως αναφέρθηκε, τα αντικείμενα μιας κλάσης εμφανίζονται στον<br />

πάγκο αντικειμένων, όπως φαίνεται στην Εικόνα 15. Κάντε κλικ με το δεξί πλήκτρο<br />

του ποντικιού πάνω στο αντικείμενο και επιλέξτε το όνομα μεθόδου που θέλετε να<br />

εκτελεστεί, όπως φαίνεται στην Εικόνα 16. Εάν η μέθοδος δέχεται παραμέτρους,<br />

το BlueJ εμφανίζει πλαίσιο διαλόγου για την εισαγωγή των παραμέτρων (Εικόνα<br />

17). Προσέξτε ώστε οι παράμετροι να έχουν το σωστό τύπο (π.χ. int, double,<br />

κλπ). Σε περίπτωση που η μέθοδος δέχεται ως παράμετρο αντικείμενο μιας<br />

κλάσης, δίνεται ως παράμετρος το όνομα του αντικειμένου, όπως αυτό εμφανίζεται<br />

στον πάγκο αντικειμένων. Αν η μέθοδος επιστρέφει τιμή, τότε αυτή εμφανίζεται σε<br />

κατάλληλο πλαίσιο διαλόγου μετά το τέλος της εκτέλεσης της μεθόδου.<br />

42


Εικόνα 16 Εκτέλεση μεθόδου<br />

Εικόνα 17. Εισαγωγή παραμέτρων σε μέθοδο<br />

Κάνοντας διπλό κλικ πάνω στο εικονίδιο ενός αντικειμένου στον πάγκο<br />

αντικειμένων εμφανίζονται οι τιμές των πεδίων του. Σε περίπτωση που το πεδίο<br />

αναφέρεται σε άλλο αντικείμενο ή πίνακα, στη θέση της τιμής του αντικειμένου<br />

εμφανίζεται ένα βέλος, όπως φαίνεται στην Εικόνα 18. Κάνοντας διπλό κλικ στο<br />

βέλος εμφανίζεται πλαίσιο διαλόγου για την επιθεώρηση του αντικειμένου στο<br />

οποίο αναφέρεται το πρώτο. Για παράδειγμα, κάνοντας διπλό κλικ στο βέλος δίπλα<br />

στο πεδίο myBasket στην Εικόνα 18 εμφανίζεται πλαίσιο διαλόγου για την<br />

επιθεώρηση του αντικειμένου myBasket;<br />

43


Εικόνα 18. Πλαίσιο διαλόγου επιθεώρησης αντικειμένου<br />

Η σειρά ενεργειών που πρέπει να ακολουθήσετε για τη δημιουργία αντικειμένων<br />

και την εκτέλεση λειτουργιών (κλήση μεθόδων) είναι η εξής:<br />

• Δημιουργία ενός ή περισσοτέρων αντικειμένων του τύπου Basket.<br />

Προτείνεται να ξεκινήσετε από ένα αντικείμενο.<br />

• Δημιουργία τόσων αντικειμένων του τύπου αγοραστή όσα και τα<br />

αντικείμενα του τύπου καλάθι που δημιουργήσατε, ορίζοντας, με τη<br />

βοήθεια της μεθόδου κατασκευαστή της κλάσης Customer, από ένα<br />

διαφορετικό καλάθι σε κάθε αγοραστή.<br />

• Δημιουργία ενός ή περισσοτέρων αντικειμένων του τύπου<br />

FirstQualityProduct και SecondQualityProduct. Δημιουργήστε ένα<br />

τουλάχιστον αντικείμενο από κάθε τύπο προϊόντος.<br />

• Δημιουργία ενός ή περισσοτέρων αντικειμένων του τύπου Seller.<br />

• Επιθεώρηση των τιμών των πεδίων των αντικειμένων που δημιουργήσατε<br />

• Εκτέλεση κατά σειρά των λειτουργιών (σεναρίων):<br />

o Ζύγιση προϊόντος<br />

o Υπολογισμός αξίας προϊόντος<br />

o Πληρωμή ποσού<br />

o<br />

o<br />

Είσπραξη ποσού<br />

Τοποθέτηση του προϊόντος στο καλάθι κάποιου συγκεκριμένου<br />

αγοραστή.<br />

Ορισμός αφηρημένων κλάσεων και μεθόδων<br />

Ο τρόπος δήλωσης abstract κλάσεων και μεθόδων περιγράφηκε παραπάνω. Η<br />

αφηρημένη κλάση Product δεν έχει αντικείμενα, αλλά αντίθετα, τα πραγματικά<br />

προϊόντα (αντικείμενα) είναι αντικείμενα της κλάσης Προϊόν Πρώτης Ποιότητας<br />

(FirstQualityProduct) ή της κλάσης Προϊόν Δεύτερης Ποιότητας<br />

(SecondQualityProduct). Η κλάση Product θα δηλωθεί ως αφηρημένη<br />

(abstract), θα υπάρξει σε αυτήν η αφηρημένη μέθοδος salePrice(). Αυτό<br />

γίνεται με δύο τρόπους: Είτε δημιουργώντας την κλάση ως abstract<br />

χρησιμοποιώντας την αντίστοιχη επιλογή του BlueJ κατά τη δημιουργία της<br />

κλάσης, είτε βάζοντας τη λέξη (μετατροπέα) abstract στον κώδικα δήλωσης της<br />

κλάσης. Με άλλα λόγια, στον κώδικα της κλάσης Product αλλάξτε τη δήλωση:<br />

public class Product<br />

{<br />

//. . .<br />

}<br />

σε<br />

public abstract class Product<br />

{<br />

//Δήλωση αφηρημένης μεθόδου<br />

44


private String name;<br />

private float price;<br />

//Επιστρέφει την τιμή μονάδας του προϊόντος<br />

public getPrice()<br />

{<br />

return this.price;<br />

}<br />

abstract double salePrice();<br />

}<br />

//. . .<br />

H αφηρημένη μέθοδος salePrice() θα υλοποιηθεί στις υποκλάσεις<br />

FirstQualityProduct και SecondQualityProduct. Πρόκειται για μια εφαρμογή<br />

του πολυμορφισμού, όπου η ίδια μέθοδος (ίδιο όνομα, ίδιος αριθμός και τύπος<br />

παραμέτρων) ορίζεται σε δύο ή περισσότερες κλάσεις μιας ιεραρχίας κλάσεων. Σε<br />

χρόνο εκτέλεσης «επιλύεται» το ζήτημα ποια από τις υλοποιήσεις της salePrice()<br />

θα κληθεί.<br />

45


Ενότητα 8η:<br />

Ζητήματα αντικειμενοστρεφούς σχεδίασης<br />

Διδακτικές ώρες: 2<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να κατανοούν τους μηχανισμούς της γλώσσας Java για την υποστήριξη της<br />

κελυφοποίησης (encapsulation)<br />

• Να κατανοούν την έννοια της υπερφόρτωσης μεθόδων.<br />

Στην περίπτωση της λειτουργίας υπολογισμός αξίας προϊόντος, θα διαπιστώσετε ότι<br />

υπολογίζεται η ίδια αξία, είτε πρόκειται για προϊόν πρώτης ποιότητας είτε για<br />

δεύτερης ποιότητας. Διορθώστε τη λειτουργία Υπολογισμός αξίας προϊόντος της<br />

κλάσης Πωλητής (Seller) με χρήση κατάλληλης μεθόδου salePrice().<br />

Μετά την εκτέλεση λειτουργιών που μεταβάλλουν τις ιδιότητες των αντικειμένων<br />

όπως: πληρωμή ποσού, είσπραξη ποσού, τοποθέτηση του προϊόντος στο καλάθι,<br />

ελέγξετε τις τιμές των αντίστοιχων ιδιοτήτων (ποσό στο πορτοφόλι, ποσό στο<br />

ταμείο, προϊόντα του καλαθιού) για να διαπιστώσετε τις μεταβολές στις αντίστοιχες<br />

τιμές.<br />

Πειραματιστείτε με τη δημιουργία περισσοτέρων αντικειμένων από κάθε κλάση και<br />

την εκτέλεση λειτουργιών επί αυτών.<br />

Με αφορμή την προσπέλαση της τιμής του προϊόντος από τη μέθοδο<br />

calculateValue της κλάσης Πωλητής, ο επιμορφωτής αναφέρεται στους<br />

μετατροπείς ορατότητας private, public και στην έννοια της κελυφοποίησης<br />

(encapsulation). Ο επιμορφωτής επισημαίνει την αναγκαιότητα της μη<br />

δυνατότητας προσπέλασης απευθείας κάποιων πεδίων κλάσεων και δίνεται ξανά η<br />

ευκαιρία να αναφερθεί στις μεθόδους ανάγνωσης και ανάθεσης τιμής, όπως αυτές<br />

παρουσιάστηκαν παραπάνω.<br />

Εξετάστε και ενδεχομένως αλλάξετε τους μετατροπείς ορατότητας των πεδίων<br />

όλων των κλάσεων ορίζοντας τα πεδία ως private, πλην των Product,<br />

FirstQualityProduct και SecondQualityProduct που ορίζονται ως protected.<br />

Δημιουργήστε μια ακόμη μέθοδο calculateValue στην κλάση Πωλητής (Seller),<br />

η οποία δέχεται ως παράμετρο ένα προϊόν και επιστρέφει την τιμή μονάδας αυτού<br />

του προϊόντος. Η μέθοδος αυτή θα καλεί στην πραγματικότητα τη μέθοδο<br />

salePrice() της κλάσης Προϊόν(Product) για τον υπολογισμό της τιμής μονάδας.<br />

Η δήλωση της μεθόδου είναι:<br />

public double calculateValue(Product aProduct)<br />

Ανάλογα με τον πραγματικό τύπο του ορίσματος της calculateValue,<br />

FirstQualityProduct ή SecondQualityProduct, εκτελείται μια διαφορετική<br />

υλοποίηση της salePrice() όπως αναφέρεται στην προηγούμενη ενότητα.<br />

Ενδεικτικά, η υλοποίηση της salePrice() στην κλάση FirstQualityProduct<br />

δίνεται από στο παρακάτω απόσπασμα<br />

public float salePrice()<br />

{<br />

return getPrice();<br />

}<br />

46


ενώ η υλοποίηση της ίδιας συνάρτησης στην κλάση SecondQualityProduct είναι<br />

public float salePrice()<br />

{<br />

return (getPrice() * (1 - discount) /(float) 100.);<br />

}<br />

Η μέθοδος getPrice() της κλάσης Product επιστρέφει την ονομαστική τιμή<br />

μονάδας του προϊόντος και ορίστηκε προηγουμένως ενώ η μεταβλητή discount<br />

αποτελεί πεδίο της κλάσης SecondQualityProduct. Λόγω των παραπάνω, ο<br />

υπολογισμός της τιμής του προϊόντος από την μέθοδο calculateValue() αποτελεί<br />

παράδειγμα πολυμορφικού υπολογισμού.<br />

47


Ενότητα 9η:<br />

Χρήση βιβλιοθήκης γραφικών της Java<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να χρησιμοποιούν τη βιβλιοθήκη γραφικών Swing της Java για τη<br />

δημιουργία απλών παραθυρικών εφαρμογών<br />

Η Java παρέχει μια εκτεταμένη βιβλιοθήκη (library) κλάσεων που προορίζεται για<br />

μια μεγάλη ποικιλία εφαρμογών: Διαπροσωπείες χρήστη (user interfaces),<br />

βοηθητικές βιβλιοθήκες με χρήσιμες δομές δεδομένων, είσοδος και έξοδος,<br />

δικτυακή επικοινωνία, κατανεμημένη επεξεργασία, δημιουργία γραφικών,<br />

πολυμέσα, κρυπτογραφία, κ.λπ. Στη συνέχεια περιγράφεται συνοπτικά η χρήση<br />

της βιβλιοθήκης κλάσεων που παρέχει η Java για τη δημιουργία παραθυρικών<br />

εφαρμογών. Έχουν ήδη περιγραφεί συχνά χρησιμοποιούμενες κλάσεις για το<br />

χειρισιμό συλλογών (λίστες, πίνακες αναζήτησης) οι οποίες χρησιμοποιούνται στις<br />

δραστηριότητες του σεμιναρίου. Σημειώνεται ότι το πλήθος και τα χαρακτηριστικά<br />

των κλάσεων της βασικής βιβλιοθήκης της γλώσσας είναι ιδιαίτερα μεγάλο. Είναι<br />

απαραίτητη η εξοικείωση με την ηλεκτρονική τεκμηρίωση αναφοράς της βασικής<br />

βιβλιοθήκης [http://java.sun.com/j2se/1.5.0/docs/api/index.html] ώστε οι<br />

επιμορφούμενοι να ανατρέχουν για τις λεπτομέρειες της χρήσης μιας κλάσης.<br />

Δημιουργία παραθυρικών εφαρμογών με το Java Swing<br />

Το Java Swing αποτελεί ένα σύνολο από κλάσεις οι οποίες υλοποιούν στοιχεία που<br />

συναντώνται σε παραθυρικές εφαρμογές, όπως παράθυρα, μενού, πλαίσια<br />

διαλόγου, κουμπιά, πεδία εισαγωγής κειμένου, κ.λπ. Για τη δημιουργία<br />

ολοκληρωμένων εφαρμογών γραφικών παρέχεται ένα ευρύτερο σύνολο κλάσεων<br />

που ονομάζονται Θεμελιώδεις Κλάσεις της Java (Java Foundation Classes - JFC).<br />

Οι κλάσεις του JFC περιλαμβάνονται στα πακέτα javax.swing και java.awt.<br />

Σημειώνεται ότι το AWT (Abstract Window Toolkit) αποτελεί προγενέστερη έκδοση<br />

του Swing και τμήμα του χρησιμοποιείται ακόμη.<br />

Συστατικά<br />

Η πλειονότητα των παραθυρικών εφαρμογών, ακόμη και οι ποιο πολύπλοκες,<br />

αποτελούνται από έναν σχετικά μικρό αριθμό συστατικών (components), τα οποία<br />

παρέχονται από το Swing. Όλα τα συστατικά είναι αντικείμενα των οποίων οι<br />

κλάσεις προέρχονται από μια βασική κλάση, την JComponent.<br />

Τα συστατικά διακρίνονται σε δύο κατηγορίες: Τα απλά συστατικά, όπως τα<br />

κουμπιά, τα πεδία εισαγωγής κειμένου, και τις αποθήκες οι οποίες χωρίς να<br />

παρέχουν από μόνες τους κάποια λειτουργικότητα χρησιμοποιούνται για την<br />

ομαδοποίηση και την τοποθέτηση άλλων συστατικών, απλών αλλά και άλλων<br />

αποθηκών 2 . Οι αποθήκες υλοποιούνται από την κλάση java.awt.Container. Με<br />

αυτό τον τρόπο σχηματίζονται ιεραρχίες αποθηκών, όπου αποθήκες περιέχουν<br />

άλλες αποθήκες και απλά συστατικά. Η κορυφή μιας τέτοιας ιεραρχίας είναι πάντα<br />

μια αποθήκη κορυφαίου επιπέδου (top-level container). Μια τέτοια αποθήκη είναι<br />

ένα αυτόνομο παράθυρο, αντικείμενο της κλάσης JFrame, ένα applet, αντικείμενο<br />

της κλάσης JApplet ή ένα πλαίσιο διαλόγου, αντικείμενο της κλάσης JDialog ή<br />

2 Στην πραγματικότητα όλα τα συστατικά του Swing, ακόμη και αυτά που αναφέρουμε ως «απλά», είναι<br />

αποθήκες, καθώς ο κοινός πρόγονός τους, η κλάση JComponent, κληρονομεί την κλάση Container. Η<br />

παραπάνω διάκριση αφορά στη συνηθισμένη λειτουργία των συστατικών στις περισσότερες εφαρμογές.<br />

Με άλλα λόγια, τα συστατικά που αναφέρουμε ως «απλά» συνήθως δεν χρησιμοποιούνται ως αποθήκες.<br />

48


εξειδικευμένων υποκλάσεών της που ορίζονται στο Swing. Η συνηθέστερη<br />

αποθήκη είναι το panel, αντικείμενο της κλάσης JPanel.<br />

Το Swing παρέχει ένα μεγάλο σύνολο από συστατικά, τα ποιο συνηθισμένα από τα<br />

οποία είναι:<br />

• Κουμπιά (κλάση JButton)<br />

• Ταμπέλες όπου εμφανίζεται σταθερό κείμενο (κλάση JLabel)<br />

• Πεδία κειμένου (κλάση JTextField)<br />

• Σύνθετα πλαίσια για την επιλογή στοιχείων (κλάση JComboBox)<br />

• Μενού για την επιλογή εντολών (κλάσεις JMenu και JMenuItem)<br />

• Περιοχές κειμένου, όπου εισάγεται μεγάλη ποσότητα μορφοποιημένου<br />

κειμένου (κλάση JTextArea)<br />

• Πάνελ, που αποτελεί την ποιο συνηθισμένη αποθήκη για την τοποθέτηση<br />

άλλων συστατικών (κλάση JPanel)<br />

Η χρήση των στοιχείων αυτών θα παρουσιαστεί αναλυτικότερα στα παραδείγματα<br />

και τις δραστηριότητες που ακολουθούν.<br />

Διάταξη - Διαχειριστές διάταξης<br />

Η θέση και το μέγεθος των συστατικών που τοποθετούνται σε μια αποθήκη<br />

καθορίζονται από αντικείμενα που ονομάζονται διαχειριστές διάταξης (Layout<br />

Managers). Κάθε αποθήκη σε μια ιεραρχία αποθηκών έχει τον δικό της<br />

προκαθορισμένο διαχειριστή αποθήκης, ο οποίος είναι δυνατόν να τροποποιηθεί με<br />

κλήση της μεθόδου setLayout της αποθήκης. Η τοποθέτηση ενός συστατικού σε<br />

μια αποθήκη γίνεται χρησιμοποιώντας τη μέθοδο add της κλάσης Container.<br />

Οι πιο κοινοί διαχειριστές αποθήκης είναι οι ακόλουθοι:<br />

GridLayout<br />

Στο GridLayout τα στοιχεία διατάσσονται σε ένα ορθογώνιο πλέγμα, με στήλες<br />

και γραμμές, και το μέγεθος των στοιχείων προσαρμόζονται στο μέγεθος του<br />

κελιού. Όλα τα συστατικά έχουν το ίδιο μέγεθος, το οποίο ισούται με το<br />

μεγαλύτερο επιθυμητό μέγεθος των συστατικών που περιέχονται στην αποθήκη. Ο<br />

αριθμός των στηλών και των γραμμών ορίζεται στον κατασκευαστή του<br />

GridLayout. Στο παράδειγμα:<br />

GridLayout myLayout = new GridLayout(5,10)<br />

ορίζεται ένα πλέγμα με 5 γραμμές και 10 στήλες. Αν δώσουμε 0 σε μια διάσταση<br />

σημαίνει ότι δεν μας ενδιαφέρει πόσα συστατικά θα στοιβαχθούν σε αυτή τη<br />

διάταξη. Έτσι, αν ορίσουμε GridLayout(5,0) και προσθέσουμε 10 αντικείμενα<br />

στην αποθήκη τότε αυτά θα διαταχθούν σε 5 γραμμές με 2 αντικείμενα σε κάθε μια<br />

γραμμή.<br />

49


Εικόνα 19. Χρήση GridLayout για τη διάταξη των πλήκτρων αριθμομηχανής<br />

Στην Εικόνα 19 τα πλήκτρα μιας αριθμομηχανής διατάσσονται σε μια αποθήκη<br />

JPanel με το όνομα pnlButtons με χρήση του GridLayout ως εξής:<br />

JPanel pnlButtons = new JPanel();<br />

GridLayout gridLayout = new GridLayout(4,4);<br />

gridLayout.setHgap(5);<br />

gridLayout.setVgap(5);<br />

pnlButtons.setLayout(gridLayout);<br />

Οι setHgap και setVgap ορίζουν την οριζόντια και κατακόρυφη απόσταση μεταξύ<br />

των στοιχείων του πλέγματος. Στη συνέχεια, τα κουμπιά δημιουργούνται και<br />

προστίθενται στο πάνελ ως εξής:<br />

JButton btnSeven = new JButton(“7”);<br />

pnlButtons.add(btnSeven);<br />

//…<br />

FlowLayout<br />

Το προκαθορισμένο σχήμα διάταξης σε ένα panel, δηλαδή αυτό που ισχύει αν δεν<br />

οριστεί ένας διαχειριστής διάταξης για αυτό, υλοποιείται από το διαχειριστή<br />

FlowLayout, που τοποθετεί τα συστατικά με το μέγεθος που αυτά προτιμούν<br />

γεμίζοντας το panel από αριστερά προς τα δεξιά και από πάνω προς τα κάτω.<br />

BorderLayout<br />

Ο διαχειριστής BorderLayout, χρησιμοποιείται για την τοποθέτηση συστατικών σε<br />

συγκεκριμένη θέση σχετικά με τα όρια μιας αποθήκης, δηλ. στο κέντρο, ή στα<br />

τέσσερα όρια της αποθήκης. Για την τοποθέτηση συστατικών σε μια αποθήκη με με<br />

αυτό το διαχειριστή διάταξης χρησιμοποιείται η μέθοδος add της αποθήκης όπως<br />

φαίνεται στο παρακάτω παράδειγμα<br />

container.setLayout(new GridLayout());<br />

container.add(top, BorderLayout.PAGE_START);<br />

container.add(left, BorderLayout.LINE_START);<br />

container.add(center, BorderLayout.CENTER);<br />

50


container.add(right, BorderLayout.LINE_END);<br />

container.add(bottom, BorderLayout.PAGE_END);<br />

όπου top, left, center, right, bottom είναι κουμπιά τα οποία τοποθετούνται<br />

στον container.<br />

Το δεύτερο όρισμα της add είναι μια αριθμητική σταθερά (μεταβλητή static<br />

final) της κλάσης BorderLayout που δηλώνει την θέση στην οποία θα τοποθετηθεί<br />

το συστατικό που αναφέρεται στο πρώτο όρισμα. Η διάταξη του παραθύρου<br />

φαίνεται στην Εικόνα 20.<br />

Εικόνα 20. Διαταξη BorderLayout<br />

Null Layout<br />

Tα συστατικά του Swing και η βιβλιοθήκη JFC προορίζονται για τη δημιουργία<br />

παραθύρων και διαπροσωπειών χρήστη σε εφαρμογές που εκτελούνται σε<br />

διαφορετικές πλατφόρμες υλικού και λογισμικού. Με αυτή την έννοια<br />

υποστηρίζεται η ρυθμιζόμενη εμφάνιση (pluggable look and feel) των στοιχείων,<br />

δηλαδή τη διαφορετική εμφάνιση των παραθύρων, κουμπιών, κ.λπ., ανάλογα με<br />

το γραφικό περιβάλλον, π.χ. Windows, Macintosh, Motif, GTK+ για περιβάλλοντα<br />

Unix, κ.λπ. Αυτό το σκοπό εξυπηρετούν οι διαχειριστές διάταξης, με τους οποίους<br />

επιτυγχάνεται η λογική διάταξη των συστατικών στην οθόνη, σε αντίθεση με τη<br />

γεωμετρική διάταξη, που συναντάται σε άλλα περιβάλλοντα ανάπτυξης. Η χρήση<br />

των διαχειριστών διάταξης για την τοποθέτηση των συστατικών του Swing<br />

επιτρέπει την ανάπτυξη μεταφέρσιμων εφαρμογών αλλά καθιστά την ανάπτυξη<br />

δυσχερή καθώς απαιτεί αρκετή εξοικείωση από τον προγραμματιστή. Για πιο<br />

εύκολο χειρισμό των παραθύρων, είναι δυνατός ο ορισμός του διαχειριστή<br />

διάταξης για μια αποθήκη στην ειδική τιμή null ως εξής:<br />

container.setLayout(null);<br />

Με τον τρόπο αυτό τα συστατικά τοποθετούνται σε απόλυτες συντεταγμένες σε<br />

σχέση με την αποθήκη στην οποία τοποθετούνται. Ο ορισμός της θέσης και<br />

μεγέθους του συστατικού γίνεται με χρήση της μεθόδου<br />

setBounds(int x, int y, int width,int height)<br />

51


του συστατικού, όπου x, y οι συντεταγμένες σε pixels που ορίζουν την απόσταση<br />

από το πάνω αριστερό άκρο της αποθήκης στην οποία τοποθετείται το στοιχείο και<br />

width και height οι διαστάσεις του συστατικού, όπως φαίνεται στο παρακάτω<br />

παράδειγμα:<br />

container.setLayout(null);<br />

JLabel lblCelcius = new JLabel("Θερμοκρασία Κελσίου:");<br />

lblCelcius.setBounds(10,10,150,20);<br />

container.add(lblCelcius);<br />

JTextField txtCelcius = new JTextField();<br />

txtCelcius.setBounds(160,10,40,20);<br />

container.add(txtCelcius);<br />

Σημειώνεται ότι η οριζόντια διάσταση (το όρισμα x της setBounds) αυξάνει από<br />

αριστερά προς τα δεξιά ενώ η κατακόρυφη, δηλ. το όρισμα y της ίδιας<br />

συνάρητησης, από πάνω προς τα κάτω. Η σύμβαση αυτή ισχύει σε όλες τις<br />

βιβλιοθήκες γραφικών της Java.<br />

Χειρισμός γεγονότων<br />

Ο ρόλος της διαπροσωπείας χρήστη μιας εφαρμογής είναι η εμφάνιση δεδομένων<br />

και η εκτέλεση εντολών του προγράμματος ως απόκριση στις ενέργειες του<br />

χρήστη. Όταν ο χρήστης επιλέγει ένα στοιχείο από ένα μενού, λίστα ή σύνθετο<br />

πλαίσιο (combo box) ή όταν πατάει ένα κουμπί, τότε το αντίστοιχο συστατικό<br />

ενεργοποιεί ένα γεγονός (event) μέσω του γραφικού περιβάλλοντος της Java. Ένα<br />

γεγονός αναπαρίσταται στην Java με ένα αντικείμενο το οποίο περιέχει πληροφορίες<br />

για το γεγονός και προσδιορίζει την πηγή του γεγονότος, δηλ. ποιο<br />

ακριβώς συστατικό ενεργοποίησε το γεγονός. Πηγές γεγονότων μπορεί να είναι<br />

συστατικά του Swing ή άλλα αντικείμενα. Κάθε συστατικό ενεργοποιεί<br />

συγκεκριμένους τύπους (κλάσεις αντικειμένων) γεγονότων.<br />

Παραδείγματα γεγονότων είναι τα γεγονότα ποντικιού (κλάση MouseEvent), που<br />

ενεργοποιούνται σε μια ενέργεια του ποντικιού πάνω σε ένα συστατικό (π.χ. το<br />

πάτημα ενός πλήκτρου του ποντικιού), γεγονότα μενού (κλάση MenuEvent) που<br />

ενεργοποιούνται κατά την επιλογή ενός στοιχείου από ένα μενού κ.λπ. Τα<br />

γεγονότα διακρίνονται σε δύο είδη: Γεγονότα χαμηλού επιπέδου, τα οποία<br />

αντιστοιχούν σε στοιχειώδεις ενέργειες όπως το πάτημα ενός κουμπιού με το<br />

πληκτρολόγιο ή το ποντίκι, και υψηλότερου επιπέδου, σημασιολογικά γεγονότα,<br />

όπως η επιλογή ενός στοιχείου από μια λίστα, η αλλαγή των στοιχείων μιας βάσης<br />

δεδομένων που εμφανίζονται σε έναν πίνακα, κ.λπ. Αυτό το σεμινάριο<br />

πραγματεύεται μόνο χαμηλού επιπέδου. Ένα γενικής φύσεως χαμηλού επιπέδου<br />

γεγονός, το οποίο χρησιμοποιείται πολύ συνηθισμένα σε εφαρμογές είναι το<br />

java.awt.event.ActionEvent, το οποίο ενεργοποιείται όταν προκύψει οποιαδήποτε<br />

δράση σε ένα συστατικό, π.χ. πάτημα κουμπιού, επιλογή στοιχείου από ένα<br />

μενού, πάτημα του πλήκτρου «Enter» κατά την εισαγωγή κειμένου σε ένα πεδίο<br />

κειμένου, κ.λπ.<br />

Για κάθε είδος γεγονότος ορίζεται από το Swing ένας ακροατής (listener) ο οποίος<br />

χειρίζεται το γεγονός (event handler). Ένας ακροατής είναι μια διαπροσωπεία<br />

(interface) της Java. Η κλάση που υλοποιεί (implement) τον αντίστοιχο ακροατή,<br />

περιέχει κώδικα με τη μορφή μεθόδων που ορίζονται στον ακροατή, ο οποίος<br />

52


κώδικας εκτελείται κατά την εμφάνιση του αντίστοιχου γεγονότος. Οι μέθοδοι του<br />

ακροατή που υλοποιούνται για το σκοπό αυτό (callback methods) δέχονται ως<br />

παράμετρο ένα αντικείμενο της κλάσης του γεγονότος που αντιστοιχεί στον<br />

ακροατή. Για παράδειγμα, η διαπροσωπεία ActionListener περιέχει τη μέθοδο<br />

public void actionPerformed(ActionEvent e)<br />

η οποία πρέπει να υλοποιηθεί ώστε να εκτελεστεί κατάλληλος κώδικας κατά την<br />

εμφάνιση του γεγονότος ActionEvent.<br />

Για την υλοποίηση κώδικα που σχετίζεται με ένα γεγονός που ενεργοποιείται από<br />

κάποιο συστατικό απαιτείται:<br />

• Η υλοποίηση του αντίστοιχου listener από μια κλάση του προγράμματος.<br />

• Η εγγραφή του αντικειμένου που υλοποιεί τον listener στους listeners του<br />

συστατικού, με την κλήση της μεθόδου addXXXListener, όπου ΧΧΧ το<br />

όνομα του listener. π.χ. button.addActionListener(myFrame).<br />

Ένα ολοκληρωμένο παράδειγμα<br />

Στη συνέχεια παρουσιάζονται τα βήματα για τη δημιουργία μιας παραθυρικής<br />

εφαρμογής με χρήση της βιβλιοθήκης της Java μέσω ενός παραδείγματος.<br />

Πρόκειται για ένα μικρό πρόγραμμα για τη μετατροπή τιμών θερμοκρασίας από την<br />

κλίμακα Κελσίου στην κλίμακα Fahrenheit, το παράθυρο του οποίου παρουσιάζεται<br />

στην Εικόνα 21.<br />

Εικόνα 21. Το παράθυρο της εφαρμογής μετατροπής θερμοκρασίας<br />

Για τη δημιουργία ενός frame για την εφαρμογή ορίζουμε μια κλάση που<br />

κληρονομεί από την κλάση JFrame<br />

public class TemperatureFrame extends JFrame {<br />

}<br />

Παρατηρήστε τη χρήση της κληρονομικότητας ως μηχανισμού για την<br />

επαναχρησιμοποίηση κώδικα για τη δημιουργία του παραθύρου.<br />

Για την αρχικοποίηση του frame γράφουμε έναν κατασκευαστή για την κλάση<br />

TemperatureFrame.<br />

Σημειώνεται ότι η κλάση JFrame δεν αποτελεί αποθήκη από μόνη της. Η αποθήκη<br />

που αντιστοιχεί στο frame λαμβάνεται με τη μέθοδο getContentPane() της<br />

κλάσης JFrame.<br />

Container container = getContentPane();<br />

53


Καθορίζουμε το μεγέθους του frame με χρήση της μεθόδου<br />

setPreferredSize(java.awt.Dimension d);<br />

Καθορίζουμε το σχήμα διάταξης της αποθήκης του frame με χρήση της μεθόδου<br />

setLayout(). Στο παράδειγμα θέτουμε διαχειριστή διάταξης null.<br />

container.setLayout(null);<br />

Στη συνέχεια προσθέτουμε τα συστατικά στο frame. Για κάθε συστατικό:<br />

• Δημιουργούμε το συστατικό. Για παράδειγμα, στο κουμπί btnConvert:<br />

JButton btnConvert = new JButton("Μετατροπή");<br />

Το όρισμα «Μετατροπή» στον κατασκευαστή καθορίζει το κείμενο που<br />

εμφανίζεται στο κουμπί. Αν χρειαστεί, ορίζουμε τις διαστάσεις και τη θέση<br />

του συστατικού<br />

btnConvert.setBounds(220,10,100,20);<br />

Πολλές φορές το βήμα αυτό δεν είναι απαραίτητο, καθώς οι επιθυμητές<br />

διαστάσεις και η θέση του συστατικού είναι δυνατόν να καθοριστούν από τα<br />

άλλα χαρακτηριστικά του συστατικού και από τον διαχειριστή αποθήκης<br />

στον οποίο θα το τοποθετήσουμε.<br />

• Τοποθετούμε το συστατικό στην αποθήκη<br />

container.add(btnConvert)<br />

• Δημιουργούμε, αν αυτό απαιτείται, έναν ακροατή (listener) ο οποίος<br />

ειδοποιείται όταν το συστατικό ενεργοποιήσει ένα event. Στη συγκεκριμένη<br />

εφαρμογή, το γεγονός που ενεργοποιείται από το πλήκτρο «Μετατροπή»<br />

είναι ένα ActionEvent. Ο αντίστοιχος ακροατής υλοποιείται από την ίδια<br />

την κλάση TemperatureFrame<br />

public class TemperatureFrame extends JFrame implements<br />

ActionListener<br />

• Τέλος, καταχωρούμε την υλοποίηση του ακροατή στους ακροατές του<br />

συστατικού. Στο παράδειγμα, το TemperatureFrame καταχωρείται στους<br />

ακροατές στους οποίους το κουμπί btnConvert «στέλνει» μηνύματα τύπου<br />

ActionEvent<br />

btnConvert.addActionListener(this);<br />

Η TemperatureFrame πρέπει να υλοποιήσει τη μέθοδο actionPerformed της<br />

διαπροσωπείας ActionListener, της οποίας ο κώδικας θα εκτελεστεί όταν<br />

ενεργοποιηθεί το αντίστοιχο event.<br />

public void actionPerformed(ActionEvent e) {<br />

double celcius =<br />

54


}<br />

Double.parseDouble(txtCelcius.getText());<br />

double fahrenheit = Converter.c2f(celcius);<br />

lblFahrenheitResult.setText(String.valueOf(fahrenheit));<br />

Η μέθοδος getText() της κλάσης JTextField επιστρέφει το κείμενο που έχει<br />

γραφεί σε ένα πεδίο κειμένου. Η static μέθοδος parseDouble(Sting arg) της<br />

κλάσης java.lang.Double επιστρέφει έναν αριθμό τύπου double ο οποίος<br />

αναπαρίσταται από τη συμβολοσειρά που δέχεται ως όρισμα.<br />

Η μέθοδος setString() ενός συστατικού ορίζει το κείμενο το οποίο εμφανίζεται<br />

από αυτό το συστατικό.<br />

Η καθεαυτό μετατροπή της τιμής της θερμοκρασίας από βαθμούς Κελσίου σε<br />

Fahrenheit γίνεται με κλήση της static μεθόδου c2f() της κλάσης Converter.<br />

Στην κλάση TemperatureFrame προστίθεται η μέθοδος main η οποία εκτελείται<br />

από το περιβάλλον εκτέλεσης της Java αν μεταγλωττίσουμε και εκτελέσουμε μια<br />

εφαρμογή. Η main περιέχει τη δημιουργία ενός αντικειμένου της κλάσης<br />

TemperatureFrame<br />

JFrame frame = new TemperatureFrame();<br />

τον υπολογισμό και τον ορισμό του μεγέθους του frame με κλήση της μεθόδου<br />

frame.pack();<br />

και τέλος την εμφάνιση του frame με κλήση της μεθόδου<br />

frame.setVisible(true);<br />

Η εφαρμογή είναι δυνατόν να μεταγλωττιστεί και να εκτελεστεί καλώντας τη<br />

μέθοδο main και μέσα από το περιβάλλον BlueJ, όπως παρουσιάστηκε σε<br />

προηγούμενη ενότητα. Εναλλακτικά, δίνουμε στη γραμμή εντολών (command<br />

prompt) των Windows τις ακόλουθες εντολές:<br />

javac TemperatureFrame.java<br />

και στη συνέχεια<br />

java TemperatureFrame<br />

Με την τελευταία εντολή εκτελείται η μέθοδος main.<br />

Στη συνέχεια παρέχεται αυτούσιος ο κώδικας των δύο κλάσεων της εφαρμογής.<br />

import javax.swing.JFrame;<br />

import javax.swing.JButton;<br />

import javax.swing.JLabel;<br />

import javax.swing.JTextField;<br />

55


import java.awt.Container;<br />

import java.awt.event.ActionListener;<br />

import java.awt.event.ActionEvent;<br />

public class TemperatureFrame extends JFrame implements<br />

ActionListener{<br />

JTextField txtCelcius;<br />

JLabel lblFahrenheitResult;<br />

public TemperatureFrame() {<br />

setTitle("Μετατροπέας Κελσίου σε Fahrenheit");<br />

setPreferredSize(new java.awt.Dimension(400,200));<br />

Container container = getContentPane();<br />

container.setLayout(null);<br />

JLabel lblCelcius =<br />

new JLabel("Θερμοκρασία Κελσίου:");<br />

lblCelcius.setBounds(10,10,150,20);<br />

container.add(lblCelcius);<br />

txtCelcius = new JTextField();<br />

txtCelcius.setBounds(160,10,40,20);<br />

container.add(txtCelcius);<br />

JButton btnConvert = new JButton("Μετατροπή");<br />

btnConvert.setBounds(220,10,100,20);<br />

btnConvert.addActionListener(this);<br />

container.add(btnConvert);<br />

JLabel lblFahrenheit= new JLabel("Θερμοκρασία :");<br />

lblFahrenheit.setBounds(10,50,150,20);<br />

container.add(lblFahrenheit);<br />

lblFahrenheitResult = new JLabel("-");<br />

lblFahrenheitResult.setBounds(160,50,150,20);<br />

container.add(lblFahrenheitResult);<br />

// Έξοδος από την εφαρμογή<br />

// με το κλείσιμο του παραθύρου<br />

56


}<br />

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />

public void actionPerformed(ActionEvent e) {<br />

double celcius =<br />

Double.parseDouble(txtCelcius.getText());<br />

double fahrenheit = Converter.c2f(celcius);<br />

lblFahrenheitResult.setText(String.valueOf(fahrenheit));<br />

}<br />

}<br />

public static void main(String[] args) {<br />

JFrame frame = new TemperatureFrame();<br />

frame.pack();<br />

frame.setVisible(true);<br />

}<br />

Η κλάση Converter.<br />

public class Converter {<br />

public static double c2f(double celcius)<br />

{<br />

return (celcius * 1.8 + 32.0) ;<br />

}<br />

}<br />

Σχεδιαστική σημείωση<br />

Παρατηρήστε ότι η μετατροπή της θερμοκρασίας δεν υλοποιείται μέσα στην κλάση<br />

TemperatureFrame, αλλά ορίζεται ως μέθοδος μιας ξεχωριστής κλάσης, της<br />

Converter η οποία αποτελεί το «λειτουργικό τμήμα» (functional part) της<br />

εφαρμογής. Αυτός ο διαχωρισμός της διαπροσωπείας χρήστη (user interface part)<br />

από το λειτουργικό τμήμα μιας εφαρμογής είναι πολύ σημαντικός για τη σωστή<br />

σχεδίαση λογισμικού. Το τμήμα της διαπροσωπείας χρήστη πρέπει να υποστηρίζει<br />

• τη μορφοποίηση και παρουσίαση δεδομένων<br />

• την απόκριση στις εντολές του χρήστη και την προώθησή τους στο<br />

λειτουργικό τμήμα της εφαρμογής με κατάλληλες κλήσεις<br />

την διενέργεια στοιχειωδών πράξεων ή ελέγχων πάνω στα δεδομένα, όπως η<br />

μετατροπή κειμένου σε αριθμητική τιμή που πραγματοποιείται μέσα στη μέθοδο<br />

actionPerformed στο συγκεκριμένο παράδειγμα.<br />

Το λειτουργικό τμήμα της εφαρμογής, το οποίο αναφέρεται στην εκτέλεση<br />

αριθμητικών υπολογισμών, την αποθήκευση και ανάκτηση δεδομένων, στις<br />

πράξεις πάνω στα δεδομένα της εφαρμογής, και γενικότερα την υλοποίηση της<br />

«λογικής της εφαρμογής» πρέπει να υλοποιείται από άλλες μονάδες (κλάσεις και<br />

πακέτα) του προγράμματος, οι οποίες επικοινωνούν με τις κλάσεις της<br />

διαπροσωπείας χρήστη μέσα από μια καλά ορισμένη διαπροσωπεία.<br />

Η ταύτιση της διαπροσωπείας χρήστη με το λειτουργικό τμήμα και η γενικότερη<br />

οργάνωση μιας εφαρμογής με βάση τις κλάσεις και τις μεθόδους της<br />

διαπροσωπείας χρήστη, π.χ. η υλοποίηση του μετατροπέα θερμοκρασίας από μια<br />

57


μεμονωμένη κλάση όπως, για παράδειγμα, η TemperatureFrame στο συγκεκριμένο<br />

παράδειγμα, πρέπει να αποφεύγεται.<br />

Ο λόγος είναι ότι με τον παραπάνω διαχωρισμό υποστηρίζεται η ανάπτυξη<br />

λογισμικού με ποιοτικά χαρακτηριστικά όπως η ευκολία στον έλεγχο και τη<br />

συντήρηση και η δυνατότητα επαναχρησιμοποίησης τμημάτων (μονάδων) του<br />

λογισμικού τα οποία είναι ιδιαίτερα σημαντικά σε εφαρμογές που πρόκειται να<br />

χρησιμοποιηθούν σε πραγματικό περιβάλλον και σε βάθος χρόνου 3 . Η αντικειμενοστρεφής<br />

σχεδίαση του λειτουργικού τμήματος καθώς και ολοκληρωμένων εφαρμογών<br />

παρουσιάζεται με μεγαλύτερη λεπτομέρεια στη συνέχεια του σεμιναρίου.<br />

Δραστηριότητα<br />

Αφού πληκτρολογήσετε, μεταγλωττίσετε και εκτελέσετε το πρόγραμμα του<br />

μετατροπέα θερμοκρασίας, αλλάξτε τις τιμές των συντεταγμένων ώστε να<br />

προκύψουν διαφορετικές διευθετήσεις των στοιχείων στο παράθυρο.<br />

Στη συνέχεια, αλλάξτε τη διάταξη των στοιχείων της οθόνης της εφαρμογής<br />

χρησιμοποιώντας ένα ή περισσότερα πάνελ και αντίστοιχους διαχειριστές διάταξης,<br />

διαφορετικούς από null. Προτείνεται η χρήση των διαχειριστών BorderLayout και<br />

GridLayout. Δεν είναι απαραίτητο να διατηρηθεί η διάταξη που φαίνεται στην<br />

Εικόνα 21, αλλά μπορείτε να πειραματιστείτε με διαφορετικές τοποθετήσεις των<br />

στοιχείων στην οθόνη. Με τη χρήση ενός διαχειριστή διάταξης διαφορετικού από<br />

τον null δεν χρησιμοποιείται η μέθοδος setBounds. Σημειώστε ότι για να ορίσετε<br />

το μέγεθος του πεδίου κειμένου txtCelcius χρησιμοποιήστε την μέθοδο<br />

setPreferredSize(java.awt.Dimension d)<br />

όπου η Dimension d αρχικοποιείται, για παράδειγμα, ως εξής:<br />

d = new java.awt.Dimension(40,20);<br />

Η δραστηριότητα αυτή να υλοποιηθεί ατομικά από κάθε επιμορφούμενο.<br />

3<br />

Ένα πλήθος συστημάτων λογισμικού προσπελάζεται σήμερα μέσω ετερογενών και συνήθως<br />

απομακρυσμένων (remote) διαπροσωπειών χρήστη, όπως παραθυρικές φόρμες, σελίδες του Ιστού,<br />

κινητές και φορητές συσκευές, κ.λπ. Γίνεται αντιληπτό ότι σε τέτοια συστήματα η μη διάκριση του<br />

λειτουργικού τμήματος από τη διαπροσωπεία χρήστη οδηγεί σε προγράμματα τα οποία είναι δύσκολο<br />

και αδύνατο να συντηρηθούν ή να τροποποιηθούν.<br />

58


Ενότητα 10η:<br />

Ανάπτυξη ολοκληρωμένης εφαρμογής<br />

Διδακτικές ώρες: 10<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να αναλύουν, να σχεδιάζουν και να υλοποιούν ολοκληρωμένες εφαρμογές<br />

με τη γλώσσα Java<br />

• Να χρησιμοποιούν συστατικά της βιβλιοθήκης της Java όπως μενού, πλαίσια<br />

διαλόγου και σύνθετα πλαίσια.<br />

Δραστηριότητα<br />

Στην δραστηριότητα αυτή ζητείται η σχεδίαση και υλοποίηση ενός συστήματος το<br />

οποίο περιγράφεται στη συνέχεια:<br />

Μια πολυκατοικία έχει έναν αριθμό διαμερισμάτων. Η πολυκατοικία εμφανίζει μια<br />

σειρά από δαπάνες:<br />

• Δαπάνη θέρμανσης, λόγω αγοράς πετρελαίου. Για τον καταμερισμό της<br />

δαπάνης ανά διαμέρισμα η δαπάνη πολλαπλασιάζεται με ένα θερμικό<br />

συντελεστή του διαμερίσματος.<br />

• Δαπάνη ανελκυστήρα, ο οποίος αφορά στη συντήρηση του ανελκυστήρα.<br />

Για τον καταμερισμό της δαπάνης ανά διαμέρισμα η δαπάνη για τον<br />

ανελκυστήρα πολλαπλασιάζεται με ένα συγκεκριμένο συντελεστή<br />

ανελκυστήρα, ο οποίος προκύπτει από την επιφάνεια και τον όροφο του<br />

διαμερίσματος.<br />

• Άλλες δαπάνες. Για τον καταμερισμό αυτής της δαπάνης ανά διαμέρισμα η<br />

δαπάνη πολλαπλασιάζεται με τον συντελεστή επιφανείας του<br />

διαμερίσματος.<br />

Στον αναλυτικό λογαριασμό, για κάθε μια δαπάνη καταγράφεται μια περιγραφή,<br />

όπου φαίνεται η περιγραφή της δαπάνης και το αντίστοιχο ποσό.<br />

Ζητείται η κατασκευή ενός προγράμματος για τον υπολογισμό και την εκτύπωση<br />

του λογαριασμού των κοινοχρήστων της πολυκατοικίας. Ο λογαριασμός θα<br />

περιλαμβάνει τα στοιχεία της πολυκατοικίας, διεύθυνση και όνομα διαχειριστή,<br />

καθώς και αναλυτική κατανομή των δαπανών για κάθε διαμέρισμα. Για κάθε<br />

διαμέρισμα θα εκτυπώνεται ο κωδικός του διαμερίσματος, το όνομα του ενοίκου<br />

του διαμερίσματος, η περιγραφή κάθε δαπάνης και το ποσό της δαπάνης που<br />

αντιστοιχεί στο διαμέρισμα καθώς και η συνολική δαπάνη κάθε διαμερίσματος.<br />

Τέλος θα εκτυπώνεται η συνολική δαπάνη της πολυκατοικίας. Το πρόγραμμα θα<br />

υλοποιηθεί στο περιβάλλον BlueJ.<br />

Ρόλοι επιμορφούμενων<br />

Οι επιμορφούμενοι οργανώνονται σε ομάδες των τριών. Η ανάλυση και σχεδίαση<br />

γίνεται από κοινού από όλη την ομάδα. Η υλοποίηση κατανέμεται στα μέλη των<br />

ομάδων όπως παρουσιάζεται στη συνέχεια στην αντίστοιχη παράγραφο.<br />

Ανάλυση<br />

Με βάση την παραπάνω περιγραφή βρίσκουμε τις οντότητες (κλάσεις) της<br />

εφαρμογής και τις ιδιότητές τους, χρησιμοποιώντας την μεθοθολογία που<br />

παρουσιάστηκε σε προηγούμενη ενότητα:<br />

Πολυκατοικία (Block)<br />

Μια πολυκατοικία έχει ένα σύνολο από διαμερίσματα και ένα σύνολο δαπανών. Οι<br />

ιδιότητες της κλάσης είναι:<br />

59


• Όνομα διαχειριστή<br />

• Διεύθυνση<br />

Διαμέρισμα (Appartment)<br />

Οι ιδιότητες της κλάσης είναι:<br />

• Κωδικός διαμερίσματος<br />

• Όνομα ενοίκου<br />

• Συντελεστής κοινοχρήστων (για τις άλλες δαπάνες)<br />

• Θερμικός συντελεστής (για τον υπολογισμό της δαπάνης θέρμανσης)<br />

• Συντελεστής ανελκυστήρα (για τον υπολογισμό της δαπάνης του<br />

ανελκυστήρα)<br />

Δαπάνη (Expense)<br />

Οι ιδιότητες της κλάσης είναι:<br />

• Περιγραφή<br />

• Ποσό δαπάνης<br />

Η κλάση δαπάνη εξειδικεύεται σε τρεις υποκλάσεις:<br />

Δαπάνη Θέρμανσης (HeatingExpense)<br />

Δαπάνη Ανελκυστήρα (ElevatorExpense)<br />

Άλλη Δαπάνη (OtherExpense)<br />

Λογαριασμός πολυκατοικίας (Bill)<br />

Η κλάση αυτή αναφέρεται στον λογαριασμό της πολυκατοικίας, ο οποίος θα<br />

προκύψει από τον υπολογισμό των κοινοχρήστων. Ο λογαριασμός πολυκατοικίας<br />

περιλαμβάνει λογαριασμούς διαμερίσματος. Τα πεδία της κλάσης είναι:<br />

• Στοιχεία πολυκατοικίας<br />

• Συνολική δαπάνη<br />

Λογαριασμός διαμερίσματος (AppartmentBill)<br />

Ο λογαριασμός διαμερίσματος έχει περιγραφές δαπανών διαμερίσματος.<br />

• Στοιχεία Διαμερίσματος<br />

• Το ποσό της συνολικής δαπάνης που αντιστοιχεί στο διαμέρισμα<br />

• Δαπάνη διαμερίσματος (AppartmentExpenseDescription)<br />

• Η περιγραφή της δαπάνης<br />

• Το ποσό που της δαπάνης που αναλογεί στο διαμέρισμα<br />

Σενάρια<br />

Τα σενάρια χρήσης του προγράμματος είναι τα παρακάτω:<br />

• Εισαγωγή στοιχείων της πολυκατοικίας<br />

• Εισαγωγή των στοιχείων διαμερισμάτων<br />

• Εισαγωγή δαπανών<br />

• Έκδοση του λογαριασμού<br />

Σχεδίαση<br />

Με βάση τις κλάσεις και τα σενάρια της ανάλυσης προχωρούμε στη σχεδίαση του<br />

προγράμματος. Οι κλάσεις της σχεδίασης είναι τριών ειδών:<br />

Κλάσεις πεδίου εφαρμογής<br />

Αυτές είναι οι παρακάτω:<br />

Block, Appartment, Expense, HeatingExpense, ElevatorExpense,<br />

GeneralExpense, Bill, AppartmentBill, AppartmentExpenseDescripiton. Οι<br />

κλάσεις αυτές προκύπτουν από τις αντίστοιχες κλάσεις της ανάλυσης.<br />

60


Κλάση διαχείρισης της εφαρμογής<br />

Ορίζεται μια κλάση BlockMgr, υπεύθυνη για την εκτέλεση των εντολών του<br />

προγράμματος, τους υπολογισμούς, κ.λπ. «μεταβιβάζοντας» τα μηνύματα από τις<br />

κλάσεις της διαπροσωπείας χρήστη στις κλάσεις του πεδίου εφαρμογής. Οι μέθοδοι<br />

της κλάσης αυτής προκύπτουν από τα σενάρια χρήσης του προγράμματος. Σε<br />

πολλά είδη εφαρμογών η χρήση μιας ή περισσοτέρων τέτοιων κλάσεων που<br />

«μεσολαβούν» μεταξύ της διαπροσωπείας χρήστη και των υπόλοιπων κλάσεων του<br />

συστήματος είναι μια καλή πρακτική. Η κλάση αυτή παρέχει την προγραμματιστική<br />

διαπροσωπεία της εφαρμογής, δηλαδή τις μεθόδους με τις οποίες<br />

πραγματοποιούνται οι λειτουργίες της εφαρμογής. Η κλάση ελέγχου μαζί με τις<br />

κλάσεις του πεδίου εφαρμογής αποτελούν το λειτουργικό τμήμα της εφαρμογής<br />

και καλό είναι να τοποθετηθούν σε ένα ξεχωριστό πακέτο, π.χ. με όνομα fp. Η<br />

διαπροσωπεία χρήστη μπορεί, με βάση τη διαπροσωπεία που παρέχει η κλάση<br />

BlockMgr, να αναπτυχθεί ανεξάρτητα από το λειτουργικό τμήμα της εφαρμογής.<br />

Αυτή η διαπροσωπεία είναι δυνατόν να χρησιμοποιηθεί για τον έλεγχο του<br />

προγράμματος (ανεξάρτητα από τη διαπροσωπεία χρήστη). Επιπλέον, επιτρέπει<br />

την ανεξάρτητη ανάπτυξη της διαπροσωπείας χρήστη από μέλη της ομάδας<br />

ανάπτυξης, παράλληλα με την ανάπτυξη του λειτουργικού μέρους της εφαρμογής.<br />

Έτσι, ένας επιμορφούμενος είναι δυνατόν να υλοποιήσει τις κλάσεις του πεδίου<br />

εφαρμογής και ένας τις κλάσεις της διαπροσωπείας χρήση οι οποίες παρουσιάζονται<br />

στη συνέχεια.<br />

Κλάσεις διαπροσωπείας χρήστη<br />

Πρόκειται για τις παρακάτω κλάσεις:<br />

MainForm, BlockDialog, AppartmentDialog, ExpenseDialog, BillDialog. Οι<br />

κλάσεις της διαπροσωπείας χρήστη τοποθετούνται σε ένα πακέτο με το<br />

όνομα ui. Οι λεπτομέρειες της υλοποίησης αυτών των κλάσεων<br />

παρουσιάζονται στη συνέχεια.<br />

Κωδικοποίηση<br />

Μια συνοπτική περιγραφή των κλάσεων του προγράμματος παρουσιάζεται στη<br />

συνέχεια. Τα αποσπάσματα κώδικα που παρατίθενται είναι ενδεικτικά και πρέπει να<br />

συμπληρωθούν κατά την εκτέλεση της δραστηριότητας από τους<br />

επιμορφούμενους.<br />

Ρόλος μελών της ομάδας κατά την κωδικοποίηση<br />

Κατά την υλοποιήση, κάθε μέλος ομάδας αναπτύσσει, μεταγλωττίζει και ελέγχει<br />

τον κώδικα για τις κλάσεις τις οποίες έχει αναλάβει.<br />

Μετά την κοινή ανάλυση και σχεδίαση, προτείνεται η εξής κατανομή της<br />

ανάπτυξης του κώδικα στους επιμορφούμενους:<br />

Ένα μέλος της ομάδας θα αναλάβει την υλοποίηση των κλάσεων της<br />

διαπροσωπείας χρήστη.<br />

Ένα μέλος της ομάδας θα αναλάβει την ανάπτυξη των εξής κλάσεων του πεδίου<br />

εφαρμογής.<br />

Ένα μέλος της ομάδας θα αναλάβει την συνένωση των μονάδων ώστε να προκύψει<br />

ολόκληρο το πρόγραμμα, καθώς και τον έλεγχο της ορθότητας του προγράμματος.<br />

Κλάση Block<br />

Τμήμα του κώδικα της κλάσης Block παρουσιάζεται στη συνέχεια.<br />

61


package fp;<br />

//imports<br />

public class Block {<br />

private String administratorName;<br />

private String address;<br />

}<br />

private Collection appartments =<br />

new Vector();<br />

private Collection expenses =<br />

new Vector();<br />

Σχέσεις μεταξύ κλάσεων<br />

Παρατηρήστε ότι η σχέση ένα προς πολλά μεταξύ της κλάσης Block και της<br />

κλάσης Appartment υλοποιείται με τη χρήση της κλάσης συλλογής Vector και της<br />

διαπροσωπείας Collection ως εξής:<br />

private Collection appartments =<br />

new Vector();<br />

Η προσθήκη ενός διαμερίσματος σε μια πολυκατοικία γίνεται τότε με χρήση της<br />

μεθόδου add της κλάσης Vector:<br />

// Μέθοδος της κλάσης Block<br />

public void addAppartment(Appartment a) {<br />

appartments.add(a);<br />

}<br />

Το ίδιο ισχύει σε κάθε τέτοια σχέση. Σημειώστε ότι οι μέθοδοι της κλάσης Block<br />

και κάθε κλάσης του πεδίου εφαρμογής καλούνται μέσω της κλάσης BlockMgr,<br />

που περιγράφεται στη συνέχεια, εκτός ίσως από τους κατασκευαστές. Ανάλογα<br />

υλοποιούνται και οι υπόλοιπες κλάσεις του πεδίου εφαρμογής.<br />

Η κλάση Appartment<br />

public class Appartment {<br />

private String code;<br />

private String residentName;<br />

private double thermalCoefficient;<br />

private double floorCoeff;<br />

private double generalCoeff;<br />

}<br />

Η κλάση Expense<br />

Η αφηρημένη κλάση Expense έχει ως πεδία τα ακόλουθα:<br />

abstract public class Expense {<br />

protected String description;<br />

62


protected double amount;<br />

}<br />

abstract double calculate(Appartment a);<br />

Επιπλέον, δηλώνει την αφηρημένη μέθοδο Calculate που χρησιμοποιείται για τον<br />

πολυμορφικό υπολογισμό των δαπανών. Οι υποκλάσεις της, HeatingExpense,<br />

ElevatorExpense και VariousExpense, υλοποιούν την παραπάνω μέθοδο. Η<br />

δημιουργία και εισαγωγή αντικειμένων τύπου Expense γίνεται με τη μέθοδο<br />

insertExpense της κλάσης BlockMgr:<br />

public Expense insertExpense(String kind,<br />

String description, double amount) {<br />

if (block == null)<br />

return null;<br />

Expense e;<br />

if (kind.equals("Διάφορα"))<br />

e = new OtherExpense(description, amount);<br />

else if (kind.equals("Πετρελαίου"))<br />

e = new HeatingExpense(description, amount);<br />

else if (kind.equals("Ανελκυστήρα"))<br />

e = new ElevatorExpense(description, amount);<br />

else<br />

return null;<br />

}<br />

block.addExpense(e);<br />

return e;<br />

Κλάση BlockMgr<br />

Οι μέθοδοι της κλάσης BlockMgr παρουσιάζονται στη συνέχεια<br />

public class BlockMgr {<br />

Block block;<br />

public Expense insertExpense(String kind, String description, double<br />

amount) {}<br />

public void insertAppartment(Appartment a) {}<br />

public void selectBlock(Block b) {}<br />

}<br />

public Bill calculateBill() {}<br />

63


Παρατηρήστε ότι οι μέθοδοι της BlockMgr αντιστοιχίζονται στα σενάρια χρήσης<br />

του προγράμματος.<br />

Η διαπροσωπεία χρήσης αλληλεπιδρά με το λειτουργικό μέρος της εφαρμογής<br />

μέσω αυτών των μεθόδων.<br />

Πολυμορφικός υπολογισμός των δαπανών: Η μέθοδος calculateBill<br />

Κάθε μια από τις κλάσεις HeatingExpense, ElevatorExpense και OtherExpense<br />

υλοποιεί την αφηρημένη μέθοδο<br />

double calculate(Appartment a)<br />

της κλάσης Expense με διαφορετικό τρόπο και ανάλογα με το είδος της δαπάνης.<br />

Ο υπολογισμός των δαπανών γίνεται από την μέθοδο calculateBill της κλάσης<br />

BlockMgr:<br />

public Bill calculateBill() {<br />

if (this.block == null)<br />

return null;<br />

Collection appartments =<br />

block.getAppartments();<br />

Collection expenses = block.getExpenses();<br />

Bill bill = new Bill(block);<br />

double totalBlockExpense = 0;<br />

double totalAppartmentExpense;<br />

for (Appartment appartment : appartments) {<br />

totalAppartmentExpense = 0.;<br />

AppartmentBill appBill =<br />

new AppartmentBill(appartment);<br />

bill.addAppartmentBill(appBill);<br />

// Calculate expense per appartment<br />

for (Expense expense : expenses) {<br />

AppartmentExpenseDescription apExpense =<br />

new AppartmentExpenseDescription(expense);<br />

appBill.addAppartmentExpense(apExpense);<br />

double expenseAmountPerAppartment =<br />

expense.calculate(appartment);<br />

}<br />

totalAppartmentExpense +=<br />

expenseAmountPerAppartment;<br />

apExpense.setPrice(expenseAmountPerAppartment);<br />

64


}<br />

}<br />

appBill.setTotal(totalAppartmentExpense);<br />

totalBlockExpense += totalAppartmentExpense;<br />

}<br />

bill.setTotal(totalBlockExpense);<br />

return bill;<br />

Στο παράδειγμα φαίνεται ότι ο υπολογισμός της δαπάνης είναι αρκετά απλός<br />

καθώς μεταβιβάζεται κάθε φορά στο κατάλληλο αντικείμενο το οποίο «γνωρίζει»<br />

την υλοποίηση μιας μεθόδου ανάλογα με την κλάση στην οποία αυτό ανήκει.<br />

Η τεχνική υπολογισμού όπου μια κλάση αναθέτει σε άλλες την εκτέλεση ενός<br />

αλγορίθμου ο οποίος δεν είναι εκ των προτέρων γνωστός ονομάζεται Strategy.<br />

Η κλάση Bill<br />

Η μέθοδος calculateBill δημιουργεί αντικείμενα της κλάσης Bill. Η κλάση αυτή<br />

έχει ως πεδία:<br />

package fp;<br />

//…<br />

public class Bill {<br />

// Συλλογή με τους λογαριασμούς των<br />

// διαμερισμάτων<br />

Collection appBills =<br />

new Vector();<br />

Block block;<br />

// Η συνολική δαπάνη για την πολυκατοικία<br />

double total;<br />

//Μέθοδοι get και set<br />

}<br />

Η κλάση AppartmentBill<br />

Η κλάση AppartmentBill έχει ως πεδία τα ακόλουθα<br />

public class AppartmentBill {<br />

protected Appartment appartment;<br />

Collection appExpenses<br />

= new Vector();<br />

}<br />

// Η συνολική δαπάνη για το διαμέρισμα<br />

private double total;<br />

// Μέθοδοι…<br />

Η κλάση AppartmentExpenseDescription<br />

Τέλος η κλάση AppartmentExpenseDescription έχει ως πεδία<br />

public class AppartmentExpenseDescription {<br />

protected Expense expense;<br />

65


Το μερίδιο της δαπάνης που αντιστοιχεί στο<br />

// συγκεκριμένο διαμέρισμα<br />

}<br />

private double price;<br />

Η μέθοδος calculateBill η οποία δημιουργεί αντικείμενα της κλάσης Bill<br />

ονομάζεται Factory Method. Οι τεχνικές Strategy και Factory Method αποτελούν<br />

«καλές πρακτικές», συνηθισμένες λύσεις σε παρόμοια προβλήματα αντικειμενοστρεφούς<br />

σχεδίασης και ονομάζονται Σχεδιαστικά Μορφήματα (Design Patterns).<br />

Σημείωση<br />

Το σύνολο των κλάσεων Bill, AppartmentExpenseDescription και<br />

AppartmentBill θα μπορούσε να αποφευχθεί στη σχεδίαση και την κωδικοποίηση.<br />

Χρησιμοποιείται για τον διαχωρισμό του τμήματος της διαπροσωπείας χρήστη της<br />

εφαρμογής από το υπολογιστικό τμήμα.<br />

Διαπροσωπεία χρήστη<br />

Στη συνέχεια παρουσιάζονται οι κλάσεις των παραθύρων της εφαρμογής.<br />

Χρήση μενού: Η κλάση MainForm<br />

Η κεντρική οθόνη (κλάση MainForm) περιέχει ένα μενού για την εμφάνιση των<br />

παραθύρων διαλόγου του προγράμματος. Η λειτουργία του μενού βασίζεται στον<br />

ακροατή ActionListener. Τμήμα του κώδικα της κλάσης παρατίθεται στη<br />

συνέχεια με σχόλια για την κατανόησή του. Φυσικά αντί του μενού είναι δυνατόν<br />

να χρησιμοποιηθούν, για παράδειγμα, μια σειρά από κουμπιά (JButtons).<br />

package ui;<br />

//Imports…<br />

public class MainForm extends JFrame implements ActionListener{<br />

JMenuBar menuBar;<br />

JMenu menu;<br />

JMenuItem mnBlock;<br />

JMenuItem mnAppart;<br />

JMenuItem mnExp;<br />

JMenuItem mnCalc;<br />

BlockMgr mgr;<br />

public MainForm()<br />

{<br />

mgr = new BlockMgr();<br />

setTitle("Εφαρμογή Έκδοσης Κοινοχρήστων");<br />

getContentPane().setPreferredSize(<br />

new Dimension(400, 300));<br />

//Δημιουργία της γραμμής μενού<br />

66


menuBar = new JMenuBar();<br />

menu = new JMenu("Αρχείο");<br />

// Εισαγωγή του μενού «Αρχείο»<br />

menuBar.add(menu);<br />

//Εισαγωγή των επιλογών του μενού<br />

mnBlock = new JMenuItem("Εισαγωγή Πολυκατοικίας");<br />

menu.add(mnBlock);<br />

mnAppart = new JMenuItem("Εισαγωγή Διαμερισμάτων");<br />

menu.add(mnAppart);<br />

//Αρχικά οι υπόλοιπες επιλογές είναι ανενεργές<br />

mnAppart.setEnabled(false);<br />

// Εισαγωγή των υπόλοιπων επιλογών<br />

// του μενού …<br />

// Προσάρτηση του μενού στο frame<br />

setJMenuBar(menuBar);<br />

mnBlock.addActionListener(this);<br />

mnAppart.addActionListener(this);<br />

mnExp.addActionListener(this);<br />

mnCalc.addActionListener(this);<br />

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />

}<br />

// Χειρισμός των επιλογών του μενού<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

JDialog dialog;<br />

Object item = e.getSource();<br />

if (item == mnBlock)<br />

{<br />

dialog = new BlockDialog(this);<br />

}<br />

else if (item == mnAppart)<br />

{<br />

dialog = new AppartmentDialog(this);<br />

}<br />

// … Υπόλοιπα else if<br />

}<br />

dialog.pack();<br />

dialog.setVisible(true);<br />

67


Η συνάρτηση main του προγράμματος<br />

public static void main(String args[])<br />

{<br />

MainForm mf = new MainForm();<br />

mf.pack();<br />

mf.setVisible(true);<br />

}<br />

}<br />

public BlockMgr getMgr() {<br />

return mgr;<br />

}<br />

Πλαίσια διαλόγου<br />

Ένα πλαίσιο διαλόγου (dialog box) είναι αντικείμενο της κλάσης JDialog. Μοιάζει<br />

με ένα παράθυρο JFrame και συνήθως χρησιμοποιείται σε συνδυασμό με frame.<br />

Υπάρχουν δύο τρόποι εμφάνισης ενός παραθύρου διαλόγου: Παράθυρα modal,<br />

κατά την εμφάνιση των οποίων μπλοκάρονται τα υπόλοιπα παράθυρα της<br />

εφαρμογής, και παράθυρα μη modal όπου η πρόσβαση σε άλλα παράθυρα της<br />

εφαρμογής είναι ελεύθερη. Η μέθοδος setModal(boolean b) προσδιορίζει αν ένα<br />

παράθυρο διαλόγου είναι modal ή όχι. Κάθε πλαίσιο διαλόγου εξαρτάται από ένα<br />

frame της κλάσης java.awt.Frame, προγενέστερης της JFrame. Ο κατασκευαστής<br />

JDialog(Frame frame) δημιουργεί ένα πλαίσιο διαλόγου που εξαρτάται από το<br />

frame που δέχεται ως όρισμα.<br />

Φόρμα Πολυκατοικίας BlockDialog<br />

package ui;<br />

//Imports…<br />

public class BlockDialog extends JDialog implements ActionListener {<br />

MainForm mainFrame;<br />

JTextField txtAdmin;<br />

JTextField txtAddress;<br />

public BlockDialog(Frame frame) {<br />

//Κλήση του κατασκευαστή της κλάσης JDialog,<br />

// υπερκλάσης της BlockDialog<br />

super(frame);<br />

//casting<br />

mainFrame = (MainForm) frame;<br />

setModal(true);<br />

Container contentPane = getContentPane();<br />

setTitle("Φόρμα Πολυκατοικίας");<br />

JPanel dataPanel = new JPanel();<br />

dataPanel.setLayout(new<br />

java.awt.GridLayout(2, 2, 5, 3));<br />

68


JLabel lblAdmin = new JLabel("Διαχειριστής:");<br />

JLabel lblAddress = new JLabel("Διεύθυνση:");<br />

txtAdmin = new JTextField();<br />

txtAdmin.setPreferredSize((new java.awt.Dimension(150, 20)));<br />

txtAddress = new JTextField();<br />

dataPanel.add(lblAdmin);<br />

dataPanel.add(txtAdmin);<br />

dataPanel.add(lblAddress);<br />

dataPanel.add(txtAddress);<br />

contentPane.add(dataPanel, BorderLayout.CENTER);<br />

JPanel buttonsPanel = new JPanel();<br />

JButton saveButton = new JButton("Αποθήκευση");<br />

saveButton.addActionListener(this);<br />

buttonsPanel.add(saveButton);<br />

contentPane.add(buttonsPanel, BorderLayout.PAGE_END);<br />

contentPane.add(new JPanel(),<br />

BorderLayout.LINE_START);<br />

contentPane.add(new JPanel(), BorderLayout.LINE_END);<br />

//Το παράθυρο κλείνει με το πάτημα του κουμπιού πάνω<br />

//δεξιά<br />

setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);<br />

}<br />

public void actionPerformed(ActionEvent e) {<br />

BlockMgr mgr = mainFrame.getMgr();<br />

Block block = new Block(txtAddress.getText(),<br />

txtAdmin.getText());<br />

// Αν εισαχθεί πολυκατοικία, ενεργοποίησε τις υπόλοιπες επιλογές<br />

// στο μενού<br />

if (block != null) {<br />

mgr.selectBlock(block);<br />

mainFrame.mnAppart.setEnabled(true);<br />

mainFrame.mnCalc.setEnabled(true);<br />

mainFrame.mnExp.setEnabled(true);<br />

}<br />

// Κλείσιμο του παραθύρου<br />

setVisible(false);<br />

}<br />

}<br />

Στο παραπάνω τμήμα κώδικα φαίνεται ο τρόπος δημιουργίας μιας πολυκατοικίας<br />

μέσα από την αντίστοιχη φόρμα.<br />

69


Φόρμα Διαμερισμάτων AppartmentDialog<br />

Ανάλογα δημιουργείται η φόρμα (πλαίσιο διαλόγου) διαμερισμάτων. Η διαφορά<br />

είναι ότι με το πάτημα του κουμπιού Αποθήκευση το παράθυρο δεν κλείνει αλλά<br />

επιτρέπει την εισαγωγή νέου διαμερίσματος «καθαρίζοντας» τα πεδία της φόρμας.<br />

Η υλοποίηση της μεθόδου actionPerformed για το χειρισμό του πατήματος του<br />

κουμπιού «Αποθήκευση» είναι ανάλογη με αυτή της φόρμας BlockDialog.<br />

Σύνθετα πλαίσια: Η Φόρμα Δαπανών ExpensesDialog<br />

Ένα σύνθετο πλαίσιο (κλάση javax.swing.JComboBox) επιτρέπει την επιλογή μιας<br />

από ένα σύνολο επιλογών. Για την επιλογή από ένα σύνολο συμβολοσειρών<br />

(String) δημιουργούμε έναν πίνακα:<br />

String[] expenseKinds =<br />

{ "Διάφορα", "Πετρελαίου", "Ανελκυστήρα" };<br />

και στη συνέχεια καλούμε τον κατασκευαστή ττης κλάσης<br />

cmbExpenseKind = new JComboBox(expenseKinds);<br />

Η επιλογή ενός στοιχείου λαμβάνεται από τη μέθοδο getSelectedItem(). Η<br />

μέθοδος επιστρέφει αντικείμενα τύπου Object, οπότε για τη λήψη του σωστού<br />

τύπου αντικειμένου χρησιμοποιείται ο μηχανισμός μετατροπής casting της Java ως<br />

εξής:<br />

String selection =<br />

(String) cmbExpenseKind.getSelectedItem();<br />

Η μέθοδος getSelectedIndex() επιστρέφει τη θέση του στοιχείου που επελέγη.<br />

Δεν χρειάζεται πάντα ο χειρισμός του γεγονότος επιλογής ενός στοιχείου από ένα<br />

πλαίσιο διαλόγου. Όταν αυτό είναι επιθυμητό, όταν δηλαδή θέλουμε να εκτελεστεί<br />

70


κάποιος κώδικας ως συνέπεια της επιλογής ενός στοιχείου από ένα σύνθετο<br />

πλαίσιο, ορίζεται ένας χειριστής ItemListener και υλοποιείται η μέθοδος<br />

public void itemStateChanged(ItemEvent ie)<br />

Στην φόρμα δαπανών, η περιγραφή της δαπάνης αλλάζει ανάλογα με την επιλογή<br />

του είδους δαπάνης. Έτσι γράφεται ένας χειριστής ItemListener, ο οποίος<br />

υλοποιείται από την κλάση της φόρμας (ExpensesDialog) η οποία υλοποιεί την<br />

μέθοδο του χειριστή ως εξής:<br />

public void itemStateChanged(ItemEvent ie) {<br />

if (cmbExpenseKind.getSelectedIndex() != 0) {<br />

// Casting<br />

txtDescription.setText("Δαπάνη " +<br />

(String) cmbExpenseKind.getSelectedItem());<br />

}<br />

} else {<br />

txtDescription.setText("");<br />

}<br />

Η φόρμα δαπανών υλοποιείται με ανάλογο τρόπο με τη φόρμα δαπανών. Με το<br />

πάτημα του πλήκτρου αποθήκευση<br />

public void actionPerformed(ActionEvent e) {<br />

//Casting<br />

String kind= (String)<br />

cmbExpenseKind.getSelectedItem();<br />

BlockMgr mgr = mainFrame.getMgr();<br />

double amount =<br />

Double.parseDouble(txtAmount.getText());<br />

}<br />

}<br />

mgr.insertExpense(<br />

kind,txtDescription.getText(),amount);<br />

txtDescription.setText("");<br />

txtAmount.setText("");<br />

71


Φόρμα εκτύπωσης λογαριασμού BillDialog<br />

Η φόρμα εκτύπωσης λογαριασμού (κλάση BillDialog) εμφανίζει τα αποτελέσματα<br />

του υπολογισμού του λογαριασμού στην οθόνη χρησιμοποιώντας ένα συστατικό<br />

JTextArea. Η μέθοδος append(String s) της κλάσης JTextArea προσθέτει τη<br />

συμβολοσειρά s στο κείμενο που εμφανίζει ένα αντικείμενό της. Ο κώδικας της<br />

κλάσης BillDialog παρουσιάζεται στη συνέχεια.<br />

public class BillDialog extends JDialog {<br />

MainForm mainFrame;<br />

JTextArea billArea = new JTextArea();<br />

public BillDialog(MainForm frame)<br />

{<br />

mainFrame = frame;<br />

setModal(true);<br />

Container contentPane = getContentPane();<br />

billArea.setEditable(false);<br />

}<br />

billArea.setPreferredSize(<br />

new java.awt.Dimension(400,400));<br />

JScrollPane scroll = new JScrollPane(billArea);<br />

contentPane.add(scroll, BorderLayout.CENTER);<br />

setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);<br />

fillText();<br />

72


public void fillText()<br />

{<br />

BlockMgr mgr = mainFrame.getMgr();<br />

Bill bill = mgr.calculateBill();<br />

billArea.append("Διεύθυνση: ");<br />

billArea.append(bill.getBlock().getAddress());<br />

billArea.append("\nΌνομα Διαχειριστή: ");<br />

billArea.append(<br />

bill.getBlock().getAdministratorName());<br />

for (AppartmentBill ab : bill.getAppartmentBills())<br />

{<br />

billArea.append("\nΔιαμέρισμα: \t" +<br />

ab.getAppartment().getCode());<br />

billArea.append("\nΈνοικος: \t" +<br />

ab.getAppartment().getResidentName());<br />

for (AppartmentExpenseDescription ae:<br />

ab.getAppartmentExpenses())<br />

{<br />

}<br />

billArea.append("\n\t" +<br />

ae.getDescription() + " " +<br />

ae.getPrice());<br />

}<br />

billArea.append("\n");<br />

billArea.append("Συνολική δαπάνη διαμερίσματος :");<br />

billArea.append(String.valueOf(ab.getTotal()));<br />

billArea.append("\t");<br />

}<br />

}<br />

billArea.append("\n\nΣυνολική Δαπάνη πολυκατοικίας: "<br />

+ bill.getTotal());<br />

Έλεγχος<br />

Κάθε μέλος μιας ομάδας είναι υπεύθυνος για τον έλεγχο της μονάδας (κλάσεων,<br />

πακέτων) που έχει αναλάβει.<br />

Συμπληρωματική Δραστηριότητα<br />

Oι κλάσεις που υλοποιούν τα πλαίσια διαλόγου της εφαρμογής BlockDialog,<br />

AppartmentDialog και ExpensesDialog περιέχουν κώδικα ο οποίος είναι κοινός<br />

και είναι δυνατόν να επαναχρησιμοποιηθεί. Υλοποιήστε τις παραπάνω κλάσεις<br />

δημιουργώντας μια υπερκλάση και κληρονομώντας από αυτή με κατάλληλο τρόπο.<br />

73


Ενότητα 11:<br />

Η διδασκαλία του αντικειμενοστρεφούς προγραμματισμού<br />

Διδακτικοί Στόχοι<br />

Μετά το τέλος της ενότητας οι επιμορφούμενοι αναμένεται:<br />

• Να γνωρίζουν παιδαγωγικά προβλήματα και παρανοήσεις των μαθητών που<br />

σχετίζονται με τον αντικειμενοστρεφή προγραμματισμό.<br />

• Να γνωρίζουν άλλα εκπαιδευτικά περιβάλλοντα αντικειμενοστρεφούς<br />

σχεδίασης και ανάπτυξης.<br />

Η διδασκαλία του Αντικειμενοστρεφούς Προγραμματισμού έχει εισαχθεί τα<br />

τελευταία χρόνια σε σχολικά και προπτυχιακά προγράμματα σπουδών. Συνήθως η<br />

διδασκαλία του πραγματοποιείται, αφού έχει προηγηθεί διδασκαλία σε αρχές<br />

δομημένου προγραμματισμού. Ανεξάρτητα της θέσης του στο πρόγραμμα<br />

σπουδών, η εκμάθηση του Αντικειμενοστρεφούς Προγραμματισμού παρουσιάζει<br />

δυσκολίες.<br />

Οι βασικές ενότητες ενός προγράμματος σπουδών που αφορά τον<br />

αντικειμενοστρεφή προγραμματισμό είναι:<br />

1. Φιλοσοφία Αντικειμενοστρεφούς Προγραμματισμού.<br />

2. Βασικές έννοιες (Κλάση, Αντικείμενο, Ιδιότητες, Μέθοδος).<br />

3. Μεταβλητές και μέθοδοι κλάσης.<br />

4. Αφαιρετικότητα – Κελυφοποίηση - Απόκρυψη πληροφορίας –<br />

Διαχωρισμός συμπεριφοράς και υλοποίησης: αφορά στις έννοιες<br />

οντοτήτων, κλάσεων και κλάσεων με διαφορετικούς τρόπους σχεδίασης.<br />

5. Κατασκευαστής – Δημιουργία αντικειμένων – Αναφορές σε αντικείμενα.<br />

6. Υπερφόρτωση μεθόδων.<br />

7. Κληρονομικότητα – Πολυμορφισμός.<br />

Η προτεινόμενη από τη βιβλιογραφία διδακτική προσέγγιση βασίζεται σε αρχές<br />

όπως «μην ξεκινάς με κενή οθόνη», «μελέτησε κώδικα», «μην ξεκινάς με την<br />

main» και «μην ξεκινάς με το γνωστό παράδειγμα “Hello World”». Οι μαθητές<br />

πρέπει να έχουν πρόσβαση σε μαθησιακό υλικό που αποτελείται από σύντομα και<br />

περιεκτικά κομμάτια θεωρίας, αντιπροσωπευτικά παραδείγματα, λυμένες ασκήσεις,<br />

δραστηριότητες σε εκπαιδευτικά περιβάλλοντα και ασκήσεις εμπέδωσης.<br />

Οι εκπαιδευτικοί πρέπει να γνωρίζουν ότι στη διεθνή βιβλιογραφία πλήθος<br />

διδακτικών προβλημάτων αναφορικά με τον αντικειμενοστρεφή προγραμματισμό<br />

είναι καταγεγραμμένα. Για παράδειγμα, από έρευνα που διεξήχθη σε μαθητές<br />

Γυμνασίου (Teif & Hazzan 2004) που παρακολούθησαν μαθήματα εισαγωγής σε<br />

αντικειμενοστρεφείς έννοιες με τη χρήση γραφικού περιβάλλοντος «χελώνας»<br />

(μικρόκοσμος) και συλλογή δεδομένων μέσω ερωτηματολογίων, εργασιών,<br />

συνεντεύξεων και παρατήρησης, προέκυψε ότι:<br />

• συγχέουν τις ιδιότητες (attributes) ενός αντικειμένου με τα μέρη (parts)<br />

από τα οποία αυτό αποτελείται και επίσης με τις ενέργειες που μπορεί να<br />

εκτελέσει<br />

• θεωρούν ότι ένα σύνολο από αντικείμενα (set of objects) π.χ. μια ομάδα<br />

ποδοσφαίρου, είναι κλάση και όχι αντικείμενο και<br />

• συγχέουν τις σχέσεις κλάσης-αντικειμένου (class-object), ιεραρχίας<br />

(hierarchy) και όλου-μέρους (whole-part).<br />

Επίσης, από έρευνα που αφορούσε στην αντίληψη περί της δημιουργίας<br />

στιγμιοτύπων (instantiation) με τον κατασκευαστή (constructor) και τους<br />

διαφορετικούς τρόπους αρχικοποίησης στιγμιοτύπων (initialization), η οποία<br />

74


διεξήχθη σε μαθητές Λυκείου (Ragonis & Ben-Ari, 2002) που παρακολούθησαν<br />

εισαγωγικά μαθήματα Αντικειμενοστρεφούς Προγραμματισμού με τη χρήση του<br />

Bluej αναδείχθηκε η δυσκολία στην κατανόηση του κατασκευαστή γενικά και της<br />

θέσης του μέσα στην κλάση, αλλά και ιδιαίτερα στις περιπτώσεις που η<br />

αρχικοποίηση γίνεται με άλλον τρόπο διαφορετικό από αυτό της χρήσης<br />

κατασκευαστή με παραμέτρους. Επίσης, κάποιοι μαθητές θεωρούσαν πως και<br />

μόνον η δήλωση του κατασκευαστή μέσα στην κλάση αρκούσε για να<br />

δημιουργηθεί ένα αντικείμενο και δυσκολεύονταν να κατανοήσουν τη σημασία του<br />

τελεστή new.<br />

Για την καλύτερη εμπέδωση των εννοιών και την πρακτική εξάσκηση, προτείνεται<br />

οι μαθητές να πραγματοποιούν δραστηριότητες κάνοντας χρήση εκπαιδευτικών<br />

εργαλείων. Τα εργαλεία που προτείνονται είναι:<br />

1. Εκπαιδευτικό Προγραμματιστικό Περιβάλλον Bluej (http://www.bluej.org/)<br />

(Kölling et al., 2003). Στις μεθοδολογίες διδασκαλίας που έχουν διατυπωθεί για<br />

την αντιμετώπιση προβλημάτων, συγκαταλέγεται και η χρήση εκπαιδευτικών<br />

προγραμματιστικών περιβαλλόντων. Τέτοιο είναι το Bluej, το οποίο και<br />

χρησιμοποιήθηκε σε αυτό το σενάριο, το οποίο εστιάζει στην αντικειμενοστρέφεια<br />

και αποτελεί ένα πλήρες περιβάλλον ανάπτυξης εφαρμογών σε Java.<br />

Σημαντικά χαρακτηριστικά του Bluej:<br />

• Είναι εύκολο στη χρήση του σε σχέση με άλλα ολοκληρωμένα περιβάλλοντα<br />

ανάπτυξης.<br />

• Βοηθάει τον επιμορφούμενο να αντιληφθεί ότι μια εφαρμογή είναι ένα<br />

σύνολο από συνεργαζόμενες κλάσεις.<br />

• Δίνει οπτική υπόσταση στις κλάσεις και τα αντικείμενα, τα οποία δεν<br />

αποτελούν απλά γραμμές κώδικα.<br />

• Διαθέτοντας μόνο τον κώδικα μιας κλάσης, είναι δυνατή η δημιουργία<br />

αντικειμένων και η εκτέλεση μεθόδων χωρίς τη συγγραφή κώδικα για το<br />

σκοπό αυτό.<br />

• Διαθέτει όψη υλοποίησης και όψη διαπροσωπείας των κλάσεων.<br />

• Εύκολο πέρασμα από το οπτικό περιβάλλον στο περιβάλλον κώδικα και<br />

εύκολη μεταγλώττιση με επισήμανση των λαθών κατευθείαν στον συντάκτη<br />

του κώδικα, με τονισμό της γραμμής του λάθους και επίδειξη του κειμένου<br />

του μηνύματος λάθους.<br />

2. Προγραμματιστικός Μικρόκοσμος Jeroo (http://www.jeroo.org/) (Sanders &<br />

Dorn 2003). Η χρήση των Προγραμματιστικών Μικρόκοσμων έχει προταθεί επίσης<br />

για την αντιμετώπιση διδακτικών προβλημάτων. Το περιβάλλον Jeroo είναι<br />

κατάλληλο για την εκμάθηση των εννοιών αντικείμενο και μέθοδος στις οποίες από<br />

κατασκευής το περιβάλλον αυτό εστιάζει.<br />

Σημαντικά χαρακτηριστικά του Jeroo:<br />

• Όλα τα συστατικά του περιβάλλοντος είναι ορατά σε ένα παράθυρο διαρκώς.<br />

• Οπτικοποίηση της εκτέλεσης του προγράμματος, με κίνηση των<br />

αντικειμένων.<br />

• Επισήμανση με διαφορετικό χρώμα της γραμμής κώδικα που εκτελείται.<br />

• Δυνατότητα βηματικής και συνεχόμενης εκτέλεσης.<br />

• Επιλογή της ταχύτητας εκτέλεσης.<br />

• Ευκολία σύνταξης της γλώσσας του περιβάλλοντος και συνάφεια της με τη<br />

Java.<br />

• Δυνατότητα εύκολης δημιουργίας πολλών διαφορετικών Island layouts (test<br />

cases) για τον έλεγχο των προγραμμάτων.<br />

• Δυνατότητα επεξεργασίας προβλημάτων με ενδιαφέρον για τους<br />

εκπαιδευόμενους και όχι προβλημάτων επεξεργασίας συμβόλων και<br />

αριθμών.<br />

75


Η επιφάνεια εργασίας του Jeroo εμφανίζεται στην Εικόνα 22.<br />

3. Προγραμματιστικός μικρόκοσμος KarelJRobot. To KarelJRobot<br />

(http://csis.pace.edu/~bergin/KarelJava2ed/karelexperimental.html) είναι ένας<br />

ακόμη μικρόκοσμος, όπου οι εντολές της γλώσσας Java και οι έννοιες του<br />

αντικειμενοστρεφούς προγραμματισμού γίνονται διαισθητικά κατανοητές μέσα από<br />

ένα κατάλληλο γραφικό περιβάλλον που προσομοιάζει σε αυτό του περιβάλλοντος<br />

της Logo.<br />

Η επιφάνεια εργασίας του KarelJRobot εμφανίζεται στην Εικόνα 23.<br />

Εικόνα 22. Το περιβάλλον Jeroo<br />

76


Εικόνα 23. Το περιβάλλον KarelJRobot<br />

77


Βιβιογραφία<br />

David J. Barnes και Michael Kölling, Objects First with Java - A Practical<br />

Ιntroduction using BlueJ, 3 η έκδοση, Prentice Hall / Pearson Education, 2006.<br />

Bruce Eckel, Thinking In Java, 3 rd edition, http://www.mindview.net/Books/TIJ/<br />

Michael Kölling, The BlueJ Tutorial, διαθέσιμο στο<br />

http://www.bluej.org/tutorial/tutorial-201.pdf<br />

Sun Microsystems, The Java Tutorial, διαθέσιμο στο<br />

http://java.sun.com/docs/books/tutorial/<br />

Ragonis, N. and Ben-Ari, M. (2002). Teaching Constructors: A Difficult Multiple<br />

Choice. In 16th European Conference on Object-Oriented Programming.<br />

Sanders D. και Dorn B. (2003), Jeroo: a tool for introducing object-oriented<br />

programming, ACM SIGCSE Bulletin, 35(1), 201-204.<br />

Satratzemi M., Xinogalos S. και Dagdilelis V. (2003), An Environment for Teaching<br />

Object-Oriented Programming: ObjectKarel, Proceedings of the 3rd IEEE<br />

International Conference on Advanced Learning Technologies (ICALT’03), 342-<br />

343.<br />

Teif M. και Hazzan O. (2004), Junior High School Students’ Perception of Object<br />

Oriented Concepts, 18th European Conference on Object-Oriented Programming,<br />

Oslo, Norway, June 2004.<br />

Barbara Liskov και John Guttag, Program Development in Java, Abstraction,<br />

Specification and Object-Oriented Design, Addison-Wesley, 2001.<br />

James Gosling, Bill Joy, Guy Steele και Gilad Bracha, The Java Language<br />

Specification, Third Edition, Addison-Wesley, 2006, επίσης διαθέσιμο στο<br />

http://java.sun.com/.<br />

Bruce E. Wampler, The Essence of Object-Oriented Programming with Java and<br />

UML, Prentice-Hall, 2000.<br />

Βασίλειος Βεσκούκης, Τεχνολογία Λογισμικού II, τόμος Β’, Ελληνικό Ανοιχτό<br />

Πανεπιστήμιο, Πάτρα 2001.<br />

Σοφοκλής Εφραιμίδης, Αντώνης Καβαρνός, Τάσος Κουτουμάνος, Βασίλης<br />

Παπαδήμος, Νίκος Παπασπύρου, Γιάννης Πατινιωτάκης και Κλειώ Σγουροπούλου,<br />

Εισαγωγή στη Γλώσσα Προγραμματισμού Java, Τεχνική Έκθεση, Εθνικό Μετσόβιο<br />

Πολυτεχνείο, Εργαστήριο Τεχνολογίας Λογισμικού, Αθήνα 1997, διαθέσιμο στο<br />

ftp://ftp.softlab.ntua.gr/pub/users/nickie/papers/efremidis-1997-ijpl-tr.ps.gz<br />

Ιστοσελίδες με υλικό αναφοράς στην Java:<br />

http://www.it.uom.gr/project/java/tutorial.htm<br />

http://www.programmingtutorials.com/java.aspx<br />

http://www.freewarejava.com/tutorials/index.shtml<br />

http://chortle.ccsu.edu/CS151/cs151java.html<br />

78

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!