Τα patterns ξεκινήσανε από τους Erich Gamma ,Richard Helm, Ralph Johnson, John Vlissides οι οποίοι εμπενεόμενοι από αντίστοιχα βιβλία αρχιτεκτονικής, αποφασίσαν να κατασκευάσουν ένα κατάλογο από software design patterns, συνταγές, προσχέδια κώδικα τα οποία συμβαίνει να εμφανίζονται πολύ συχνά. Το βιβλίο εκδόθηκε το 1995 με τίτλο: Design Patterns: Elements of Reusable Object-Oriented Software και οι συγγραφείς γίνανε γνωστοί ως η συμμορία των τεσσάρων: Gang of Four (GoF).
Σχετικά με το Composite τώρα:
ας υποθέσουμε ότι θέλετε να κατασκευάσετε μια εφαρμογή που να υπολογίζει το συνολικό μέγεθος ενός καταλόγου στον δίσκο, ο οποίος με την σειρά του περιέχει άλλα αρχεία και άλλους καταλόγους που αναδρομικά περιέχουν δικά τους αρχεία και καταλόγους κτλ. κτλ. κτλ. Πως υπολογίζετε το συνολικό μέγεθος αυτών των αρχείων, χωρίς να καταλήξετε σε μια πληθώρα από for-if-else? Εδώ έρχεται σε βοήθεια το Composite pattern.
Απλουστεύοντας, δύο είναι οι βασικές οντότητες σε ένα σύστημα αρχείων:
- Οι κατάλογοι: folders που περιέχουν άλλους καταλόγους και αρχεία και το μέγεθός τους αποτελείται από το άθροισμα του μεγέθους των ῾παιδιών῾ αρχείων που περιέχουν.
- Τα αρχεία: files που έχουν μέγεθος αλλα δεν περιέχουν άλλα αρχεία ή καταλόγους.
/**** Interface Node - our component! *****/
public interface Node {
long calculateSize();
}
Το composite pattern βασίζεται στην έννοια του component. Το component είναι κατουσία ένα interface που ορίζει την μέθοδο (ή μεθόδους) που μας ενδιαφέρει.
Ορίζουμε λοιπόν τις εξής κλάσεις που υλοποιούν το interface Node:
/**** Class File - The leaf ****/
public class File implements Node {
private long size = 0;
private String name;
public File(String name, long size) {
this.size = size;
this.name = name;
}
public long calculateSize() {
return this.size;
}
}
private long size = 0;
private String name;
public File(String name, long size) {
this.size = size;
this.name = name;
}
public long calculateSize() {
return this.size;
}
}
/*** Class Folder - The composite **/
public class Folder implements Node {
private String name;
/** The list of children nodes. */
private List childrenNodes = null;
/** Constructor. */
public Folder(String name) {
this.name = name;
this.childrenNodes = new ArrayList();
}
/** Calculates the total size. */
public long calculateSize() {
long totalSize = 0;
for (Node node : childrenNodes) {
totalSize += node.calculateSize();
}
return totalSize;
}
public void addNode(Node node) {
childrenNodes.add(node);
}
public void removeNode(Node node) {
childrenNodes.remove(node);
}
public String getName() {
return name;
}
}
Από τις παραπάνω κλασεις το Folder είναι το composite γιατί είναι composed από πολλά άλλα στοιχεία-nodes. Το File είναι ένα απλο leaf το οποίο δεν έχει δικά του παρακλάδια. Η χρήση του κοινού interface θα μας βοηθήσει να υπολογίσουμε το συνολικό μέγεθος χωρίς την χρήση for-if-else ως εξής:
public class Client {
public static void main(String[] args) {
Folder root = new Folder("root");
File rootLog = new File("root-log.log", 100);
root.addNode(rootLog);
Folder home = new Folder("home");
File homeLog = new File("home-log.log", 200);
home.addNode(homeLog);
Folder homeUserA = new Folder("homeUserA");
File fileOfUserA = new File(".bashrc", 3);
homeUserA.addNode(fileOfUserA);
home.addNode(homeUserA);
Folder homeUserB = new Folder("homeUserB");
File fileOfUserB = new File(".bashrc", 7);
homeUserB.addNode(fileOfUserB);
home.addNode(homeUserB);
root.addNode(home);
Folder usr = new Folder("usr");
File usrLog = new File("usr-log.log", 50);
usr.addNode(usrLog);
root.addNode(usr);
System.out.println("Total: " + root.calculateSize());
}
}
Το pattern έχει αρκετές παραλλαγές που ταιριάζουν ανάλογα με την περίσταση. Για περισσότερες λεπτομέρεις μπορείτε απλά να google-αρετε αλλά το βιβλίο των G0F είναι το καλύτερο, απλα χρησιμοποιεί C++ κυρίως που ίσως δυσκολέψει.
Να σημειώσω ότι τα patterns δεν είναι πανάκοια. Είναι συνταγές για την συγγραφή κώδικα και τπτ άλλο και δεν πρέπει να γίνονται αυτοσκοπός αλλα το μέσω επίλυσης προβλημάτων. Για περισσότερες πληροφορίες σχετικά με την Java υπάρχει το site του Jhug με αρκετό υλικό για κάθε επίπεδο.
public class Folder implements Node {
private String name;
/** The list of children nodes. */
private List
/** Constructor. */
public Folder(String name) {
this.name = name;
this.childrenNodes = new ArrayList
}
/** Calculates the total size. */
public long calculateSize() {
long totalSize = 0;
for (Node node : childrenNodes) {
totalSize += node.calculateSize();
}
return totalSize;
}
public void addNode(Node node) {
childrenNodes.add(node);
}
public void removeNode(Node node) {
childrenNodes.remove(node);
}
public String getName() {
return name;
}
}
Από τις παραπάνω κλασεις το Folder είναι το composite γιατί είναι composed από πολλά άλλα στοιχεία-nodes. Το File είναι ένα απλο leaf το οποίο δεν έχει δικά του παρακλάδια. Η χρήση του κοινού interface θα μας βοηθήσει να υπολογίσουμε το συνολικό μέγεθος χωρίς την χρήση for-if-else ως εξής:
public class Client {
public static void main(String[] args) {
Folder root = new Folder("root");
File rootLog = new File("root-log.log", 100);
root.addNode(rootLog);
Folder home = new Folder("home");
File homeLog = new File("home-log.log", 200);
home.addNode(homeLog);
Folder homeUserA = new Folder("homeUserA");
File fileOfUserA = new File(".bashrc", 3);
homeUserA.addNode(fileOfUserA);
home.addNode(homeUserA);
Folder homeUserB = new Folder("homeUserB");
File fileOfUserB = new File(".bashrc", 7);
homeUserB.addNode(fileOfUserB);
home.addNode(homeUserB);
root.addNode(home);
Folder usr = new Folder("usr");
File usrLog = new File("usr-log.log", 50);
usr.addNode(usrLog);
root.addNode(usr);
System.out.println("Total: " + root.calculateSize());
}
}
Το pattern έχει αρκετές παραλλαγές που ταιριάζουν ανάλογα με την περίσταση. Για περισσότερες λεπτομέρεις μπορείτε απλά να google-αρετε αλλά το βιβλίο των G0F είναι το καλύτερο, απλα χρησιμοποιεί C++ κυρίως που ίσως δυσκολέψει.
Να σημειώσω ότι τα patterns δεν είναι πανάκοια. Είναι συνταγές για την συγγραφή κώδικα και τπτ άλλο και δεν πρέπει να γίνονται αυτοσκοπός αλλα το μέσω επίλυσης προβλημάτων. Για περισσότερες πληροφορίες σχετικά με την Java υπάρχει το site του Jhug με αρκετό υλικό για κάθε επίπεδο.