java:inheritance_subclassing_vs_encapsulating

Κριτήριo χρήσης της κληρονομικότητας ως εργαλείο ανάπτυξης λογισμικού

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

Πριν ξεκινήσουμε την υλοποίηση θα πρέπει να αποφασίσουμε εάν θέλουμε να δημιουργήσουμε το κυβοειδές χρησιμοποιώντας ως μεταβλητή της νέας κλάσης ένα αντικείμενο της κλάσης Rectangle ή επιθυμούμε να επεκτείνουμε την κλάση Rectangle μέσω της νέας κλάσης. Δείτε παρακάτω τις δύο παραλλαγές της κλάσης Cuboid με και χωρίς κληρονομικότητα.

Cuboid.java
public class Cuboid {
  Rectangle rec;
  int length;
 
  public Cuboid(int l, int w, int h) {
    rec = new Rectangle(w,h);
    length = l;
  }
 
  public int getLength() { return length; }
  public void setLength(int l) { length = l; }
 
  public int volume() { return length * rec.area(); }
}

ή

Cuboid.java
public class Cuboid extends Rectangle {
  int length;
 
  public Cuboid(int l, int w, int h) {
    super(w,h);
    length = l;
  }
 
  public int getLength() { return length; }
  public void setLength(int l) { length = l; }
 
  public int volume() { return length * area(); }
}

Οι παραπάνω δύο κλάσεις μεταγλωττίζονται και παράγουν το ίδιο λειτουργικό αποτέλεσμα. Το ερώτημα είναι ποια από τις δύο προσεγγίσεις θα προτιμήσουμε. Η απάντηση είναι απλή και συνίσταται στο εξής:

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

Στο παραπάνω παράδειγμα, εάν η κλάση Cuboid κληρονομεί την κλάση Rectangle θα πρέπει η κλάση Cuboid να είναι και τύπου Rectangle. Αν και η κλάση του κυβοειδούς μπορεί να ενσωματώσει στην περιγραφή της και ένα ορθογώνιο παραλληλόγραμμο, το κυβοειδές δεν είναι ορθογώνιο παραλληλόγραμμο. Γενικότερα, ένα τρισδιάστατο σχήμα δεν μπορεί να είναι και διδιάστατο. Δεν μπορούμε να πάμε από το κυβοειδές προς το ορθογώνιο παραλληλόγραμμο διατηρώντας τις βασικές ιδιότητες του κυβοειδούς. Το κυβοειδές αποτελεί μία εντελώς νέα οντότητα σε σχέση με το ορθογώνιο παραλληλόγραμμο. Μπορούμε να εκφράσουμε το κυβοειδές με την χρήση της κλάσης ενός ορθογώνιου παραλληλογράμμου, χωρίς όμως η χρήση του ορθογωνίου παραλληλογράμμου να είναι απαραίτητη ή να συνδέεται άμεσα με το κυβοειδές. Επομένως, η χρήση της κληρονομικότητας στο παραπάνω παράδειγμα εισάγει λογική αντίφαση.

Αντίθετα, στο αρχικό παράδειγμα της κληρονομικότητας, από την κλάση Bicycle προκύπτουν οι κλάσεις MountainBike, RoadBike και TandemBike. Και οι 3 νέες κλάσεις είναι τύπου Bicycle, καθώς αποτελούν εξειδικεύσεις της γενικής κλάσης του ποδηλάτου. Επομένως, εδώ η κληρονομικότητα συνιστάται ως μέθοδος δημιουργίας των νέων τύπων δεδομένων.

java/inheritance_subclassing_vs_encapsulating.txt · Last modified: 2017/02/16 13:31 by gthanos