Σχεδιαστικόν Πρότυπον
Ένα σχεδιαστικό πρότυπο ορίζεται ως μία αποδεδειγμένα καλή λύση που έχει εφαρμοστεί με επιτυχία στην επίλυση ενός επαναλαμβανόμενου προβλήματος Σχεδίασης Συστημάτων Λογισμικού.
Ετυμολογία[]
Η ονομασία " Σχεδιαστικό" σχετίζεται ετυμολογικά με την λέξη "σχέδιο ".
Εισαγωγή[]
Τα πρότυπα σχεδίασης ορίζονται τόσο σε επίπεδο μακροσκοπικής σχεδίασης όσο και σε επίπεδο υλοποίησης, ενώ με τη χρήση τους ένας προγραμματιστής αντικαθιστά πρακτικώς μεγάλα τμήματα του κώδικα του με μαύρα κουτιά. Πρόκειται για αφαιρέσεις υψηλού επιπέδου που αποτελούν πλήρη υποσυστήματα, κατάλληλα ρυθμισμένα για την επίλυση συγκεκριμένων προβλημάτων σχεδίασης λογισμικού και έτοιμα για χρήση.
Ιστορικό[]
Κατά τα τέλη της δεκαετίας του 1970 ένας αρχιτέκτονας ονόματι Κρίστοφερ Αλεξάντερ επιχείρησε να αναζητήσει και να καταγράψει αποδεδειγμένα ποιοτικούς σχεδιασμούς στον τομέα των κατασκευών.
Έτσι μελέτησε πολλές διαφορετικές κατασκευές που εξυπηρετούσαν τον ίδιο σκοπό και προσπάθησε να ανακαλύψει κοινά στοιχεία, τα οποία κατηγοριοποίησε σε σχεδιαστικά πρότυπα.
Το 1987 η ιδέα της εύρεσης σχεδιαστικών προτύπων εφαρμόστηκε για πρώτη φορά στη μηχανική λογισμικού και μέχρι τα μέσα της δεκαετίας του '90 η εν λόγω έννοια είχε καθιερωθεί και εξαπλωθεί, προσανατολισμένη πλέον προς τον αντικειμενοστρεφή προγραμματισμό. Ιδιαίτερα σημαντική εξέλιξη προς αυτή την κατεύθυνση υπήρξε η έκδοση του βιβλίου Design Patterns: Elements of Reusable Object-Oriented Software των Erich Gamma, Richard Helm, Ralph Johnson και John Vlissides, το 1994. Οι τέσσερις αυτοί συγγραφείς αναφέρονται στη βιβλιογραφία ως "Συμμορία των Τεσσάρων" (Gang of Four) λόγω αυτού του βιβλίου.
Πρότυπα[]
Συνήθως τα σχεδιαστικά πρότυπα κατηγοριοποιούνται σε κατασκευαστικά (creational), δομικά (structural) και συμπεριφορικά (behavioral). Η κατηγοριοποίηση αυτή απαντάται ήδη από την εποχή της Συμμορίας των Τεσσάρων. Τα παραδείγματα κώδικα που παρέχονται παρακάτω είναι σε γλώσσα προγραμματισμού Java.
Κατασκευαστικά πρότυπα[]
Τα κατασκευαστικά πρότυπα αφορούν τυποποιημένους τρόπους δυναμικής κατασκευής αντικειμένων κατά το "χρόνο εκτέλεσης". Απώτερος στόχος τους είναι η ανεξαρτητοποίηση του κώδικα που χρησιμοποιεί κάποια αντικείμενα από τις κλάσεις που ορίζουν τα αντικείμενα και τον τρόπο που αυτά δημιουργούνται στη μνήμη, σύμφωνα με την αρχή ανοικτότητας-κλειστότητας για ορθή αντικειμενοστρεφή σχεδίαση. Ακολουθούν τα σπουδαιότερα κατασκευαστικά πρότυπα:
Factory[]
Το πρότυπο αυτό συγκεντρώνει σε μία κατάλληλη κλάση, το Factory, όλη τη λειτουργικότητα κατασκευής στιγμιοτύπων μίας σειράς κλάσεων που κληρονομούν κάποια κοινή Υπερκλάση ή υλοποιούν την ίδια Διασύνδεση. Έτσι το πρόγραμμα μπορεί να καλεί τις Μεθόδους του Factory για να λάβει το ζητούμενο κατά περίπτωση αντικείμενο, χωρίς να χρειάζεται το ίδιο να γνωρίζει κάθε πιθανό τύπο δεδομένων. Με αυτόν τον τρόπο το πρόγραμμα είναι κλειστό ως προς πιθανές επεκτάσεις ενώ το Factory είναι ανοικτό ως προς αυτές, καθώς μόνο ο δικός του κώδικας χρειάζεται να τροποποιηθεί σε περίπτωση π. χ. προσθήκης μίας νέας κλάσης.
Το Factory συνήθως παρέχει μία μέθοδο για κάθε δυνατό τύπο επιστροφής, αλλά μία παραλλαγή ονόματι παραμετροποιημένο Factory παρέχει μία μοναδική μέθοδο η οποία επιλέγει το αντικείμενο που θα δημιουργήσει και θα επιστρέψει αναλόγως με την τιμή ενός ορίσματος που δέχεται.
Ένας εναλλακτικός τύπος Factory είναι όταν ορίζεται ως αφηρημένη κλάση και η παρεχόμενη μέθοδος κατασκευής αντικειμένων υποσκελίζεται από υποκλάσεις του, έτσι ώστε η καθεμία από τις τελευταίες να κατασκευάζει αντικείμενο διαφορετικού τύπου. Σε κάθε περίπτωση στόχος είναι να μπορεί το πρόγραμμα να δημιουργεί στιγμιότυπα κλάσεων χωρίς να προσδιορίζει ρητά τον ακριβή τύπο τους και αφήνοντας το Factory να τον αποφασίσει εσωτερικά.
Υπάρχει ωστόσο και μία εναλλακτική, αρκετά διαφορετική περίπτωση όπου, αντί το Factory να δηλώνεται ως κάποια/ες διακριστή/ες κλάση/εις, αποτελείται απλώς από μία ή περισσότερες στατικές μεθόδους της κλάσης από την οποία πρέπει να κατασκευάζει αντικείμενα (έστω της κλάσης Α). Τότε ο κατασκευαστής (constructor) της κλάσης δηλώνεται ως ιδιωτική μέθοδος ώστε κάθε απόπειρα του εξωτερικού προγράμματος να δημιουργήσει στιγμιότυπα της Α να γίνεται αναγκαστικά μέσω των μεθόδων Factory οι οποίες επιστρέφουν ένα νέο αντικείμενο τύπου Α.
Σε αυτήν την περίπτωση όμως η Α δεν μπορεί να κληρονομηθεί, αφού για το σκοπό αυτό πρέπει να υπάρχει τουλάχιστον ένας δημόσιος κατασκευαστής της. Ακολουθεί ένα απλό παράδειγμα παραμετροποιημένου Factory:
interface Logger
{
public void log(String msg);
}
class ConsoleLogger implements Logger
{
public void log(String msg)
{
System.err.println("\nConsole logging..." + msg + "\n");
}
}
class FileLogger implements Logger
{
public void log(String msg)
{
System.out.println("\nFile logging..." + msg + "\n");
}
}
public class LoggerFactory
{
public Logger getLogger(String choice)
{
if(choice.equals("FileLogger"))
return new FileLogger();
else if(choice.equals("ConsoleLogger"))
return new ConsoleLogger();
else
{
System.err.println("\nError. Exiting...");
return null;
}
}
}
public class LogTest
{
public static void main(String[] args)
{
if(args.length != 1)
{
System.out.println("\nError. Exiting...");
return;
}
LoggerFactory fac = new LoggerFactory();
String choice = args[0];
Logger logg = fac.getLogger(choice);
logg.log("Log This!");
}
}
Στον κώδικα αυτόν η κλάση LoggerFactory είναι η μόνη που γνωρίζει τους διαφορετικούς τύπους δεδομένων οι οποίοι υλοποιούν τη διασύνδεση Logger, άρα είναι και το μόνο σημείο του κώδικα που χρειάζεται να τροποποιηθεί σε περίπτωση που η Logger επεκταθεί με ακόμα μία κλάση. Το εξωτερικό πρόγραμμα, η κλάση LogTest, χειρίζεται απλώς ένα αντικείμενο του γενικού τύπου Logger και αφήνει στο Factory την απόφαση για τον πραγματικό τύπο του, αναλόγως με ένα όρισμα γραμμής εντολών που δίνεται από το χρήστη.
Ακολουθεί ένα παράδειγμα ορισμού του Factory ως μεθόδου μίας κλάσης την οποία πρέπει να παράγει:
class Complex
{
public static Complex fromCartesian(double real, double imag) {
return new Complex(real, imag);
}
public static Complex fromPolar(double modulus, double angle) {
return new Complex(modulus * cos(angle), modulus * sin(angle));
}
private Complex(double a, double b) {}
}
Complex c = Complex.fromPolar(1, pi); //Αντί για την τυπική κλήση Complex c = new Complex(...) η
//οποία θα μπορούσε να γίνει αν ο κατασκευαστής ήταν δημόσιος
Abstract Factory[]
Singleton[]
Το Singleton είναι ένα σχεδιαστικό πρότυπο που επιλύει το ζήτημα της εξασφάλισης της ύπαρξης το πολύ ενός στιγμιότυπου κάποιας κλάσης Α κατά το χρόνο εκτέλεσης, ένας περιορισμός που μπορεί να ανακύψει για διάφορους λόγους. Με το πρότυπο Singleton η αρμοδιότητα για την ικανοποίηση αυτού του περιορισμού ανατίθεται στην ίδια την κλάση Α και δε μεταβιβάζεται στο εξωτερικό πρόγραμμα που τη χρησιμοποιεί. Αυτό γίνεται μέσω μίας στατικής δημόσιας μεθόδου της Α η οποία δημιουργεί το πρώτο στιγμιότυπο της κλάσης και ακολούθως, σε κάθε επόμενη κλήση της, επιστρέφει έναν δείκτη ή μία αναφορά προς αυτό. Το Singleton διαφέρει από μία απλή καθολική μεταβλητή (global variable), η οποία επίσης δημιουργείται αναγκαστικά μόνο μία φορά καθ' όλο το χρόνο εκτέλεσης του προγράμματος, καθώς το αντικείμενο Singleton δε δεσμεύει μνήμη μέχρι τη στιγμή της πρώτης κλήσης της μεθόδου κατασκευής. Από εκεί κι έπειτα όμως το αντικείμενο παραμένει στη μνήμη ως τον τερματισμό του προγράμματος γιατί είναι υλοποιημένο ως στατική μεταβλητή. Ακολουθεί ένα απλό παράδειγμα:
public class A
{
private static A instance;
private A() {} //Ο κατασκευαστής ο οποίος μπορεί να κληθεί μόνο από κώδικα της ίδιας της Α
public static A getAObject()
{
if (instance == null)
{
instance = new A();
}
return instance;
}
}
Η Α περιέχει ένα στατικό γνώρισμα instance τύπου Α και μία στατική δημόσια μέθοδο getAObject η οποία ελέγχει αν στο γνώρισμα αυτό έχει ανατεθεί τιμή. Αν ναι επιστρέφει το ίδιο το γνώρισμα, διαφορετικά δημιουργεί ένα νέο στιγμιότυπο της ίδιας της κλάσης Α και το αναθέτει στο πεδίο instance προτού επιστρέψει το τελευταίο. Ο κατασκευαστής είναι ιδιωτικός ώστε να παρακάμπτεται αναγκαστικώς από το εξωτερικό πρόγραμμα και να χρησιμοποιείται πάντα η μέθοδος getAObject.
Εσωτερική Αρθρογραφία[]
- προγραμματισμός
- [[ ]]
Βιβλιογραφία[]
- Σχεδιαστικά Πρότυπα, Απόστολος Ζάρρας, Λέκτορας Πανεπιστημίου Ιωαννίνων,
- Core Techniques and Algorithms in Game Programming, Daniel Sanchez-Crespo Dalmeau, Εκδόσεις New Riders
Ιστογραφία[]
Κίνδυνοι Χρήσης |
---|
Αν και θα βρείτε εξακριβωμένες πληροφορίες "Οι πληροφορίες αυτές μπορεί πρόσφατα Πρέπει να λάβετε υπ' όψη ότι Επίσης, |
- Μην κάνετε χρήση του περιεχομένου της παρούσας εγκυκλοπαίδειας
αν διαφωνείτε με όσα αναγράφονται σε αυτήν
- Όχι, στις διαφημίσεις που περιέχουν απαράδεκτο περιεχόμενο (άσεμνες εικόνες, ροζ αγγελίες κλπ.)