JAVA ΕΝΟΤΗΤΑ 20 – PACKAGES AND ACCESS SPECIFIERS (Part 1)

 


ΕΙΣΑΓΩΓΗ

Στο σημερινό δωρεάν μάθημα Java, δούμε σε τι ακριβώς χρησιμεύουν τα packages και πως σε συνδυασμό με τα access specifiers μπορούμε να δημιουργήσουμε secure κώδικα.

SIMPLE EMPLOYEE PROGRAM

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

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

Δωρεάν μαθήματα Java

Τώρα ας ανοίξουμε αυτό το φάκελο με το VS Code και ας δημιουργήσουμε ένα καινούργιο Java Maven Project με το όνομα EmployeeApp, όπως ακριβώς έχετε ήδη μάθει από την JAVA ENOTHTA 2 – JAVA MAVEN PROJECT CREATION. Όταν τελειώσετε αυτή τη διαδικασία θα έχει δημιουργηθεί ένα απλό Maven project μέσα στο φάκελο packagedemo.

Δωρεάν μαθήματα Java

Δωρεάν μαθήματα Java


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

Για αρχή ας δημιουργήσουμε μια κλάση με το όνομα Taxes, στο ίδιο πακέτο που βρίσκεται και η App.java κλάση, μέσα από την οποία μπορούμε να υπολογίσουμε τους φόρους από το μισθό του εργαζόμενου. Επειδή ο υπολογισμός των φόρων μπορεί να είναι μια πολύπλοκη διαδικασία, αποφασίζουμε να αναπτύξουμε τον κώδικα σε μια ξεχωριστή κλάση από της οποίας τα αντικείμενα θα έχουν την δυνατότητα υπολογισμού του φόρου. Όπως ήδη γνωρίζετε, αυτό τους είδους οι αλγόριθμοι θα βρίσκονται μέσα σε μια ή περισσότερες μεθόδους.

Αφού δημιουργήσετε την κλάση Taxes, προσθέστε δύο instance variables με τα ονόματα grossIncome (ετήσιος μισθός) και dependents (εξαρτώμενα μέλη) με data types double και int αντίστοιχα.

Taxes.java

package com.example;

public class Taxes {
    double grossIncome; // class member variables
    int dependents;
}

Επειδή δεν επιθυμούμε να δημιουργούμε αντικείμενα είδος Taxes χωρίς αρχικές τιμές, γράφουμε τον δικό μας constructor που απαιτεί την εισαγωγή και των δύο τιμών των μεταβλητών πριν δημιουργηθεί το αντικείμενο. Όπως ήδη γνωρίζετε, όταν δημιουργήσουμε τον δικό μας constructor, τότε ο no-argument  constructor δεν είναι πια διαθέσιμός από την Java εκτός αν τον δημιουργήσουμε πάλι εμείς. Επίσης, εκτός από τον constructor θέλουμε να προσθέσουμε και getter και setter μεθόδους.

Taxes.java

package com.example;

public class Taxes {
    double grossIncome; // class member variables
    int dependents;

    public Taxes(double grossIncome, int dependents) {
        this.grossIncome = grossIncome;
        this.dependents = dependents;
    }

    public double getGrossIncome() {
        return this.grossIncome;
    }

    public void setGrossIncome(double grossIncome) {
        this.grossIncome = grossIncome;
    }

    public int getDependents() {
        return this.dependents;
    }

    public void setDependents(int dependents) {
        this.dependents = dependents;
    }

}


Τώρα που υπάρχουν οι getters και setters μέθοδοι, ας αλλάξουμε την πρόσβαση στις instance variables έτσι ώστε οι τιμές τους να αλλάζουν μόνο δια μέσω των getter και setters.

Taxes.java

package com.example;

public class Taxes {
    private double grossIncome; // class member variables
    private int dependents;

    public Taxes(double grossIncome, int dependents) {
        this.grossIncome = grossIncome;
        this.dependents = dependents;
    }

    public double getGrossIncome() {
        return this.grossIncome;
    }

    public void setGrossIncome(double grossIncome) {
        this.grossIncome = grossIncome;
    }

    public int getDependents() {
        return this.dependents;
    }

    public void setDependents(int dependents) {
        this.dependents = dependents;
    }

}

Αυτό που λείπει για την ολοκλήρωση της κλάσης Taxes είναι μια μέθοδος υπολογισμού των φόρων. Ας δημιουργήσουμε λοιπόν μια καινούργια μέθοδο με το όνομα calcTax( ) που θα περιέχει τον εξής κώδικα:

Taxes.java

package com.example;

public class Taxes {
    private double grossIncome; // class member variables
    private int dependents;

    public Taxes(double grossIncome, int dependents) {
        this.grossIncome = grossIncome;
        this.dependents = dependents;
    }

    public double getGrossIncome() {
        return this.grossIncome;
    }

    public void setGrossIncome(double grossIncome) {
        this.grossIncome = grossIncome;
    }

    public int getDependents() {
        return this.dependents;
    }

    public void setDependents(int dependents) {
        this.dependents = dependents;
    }

    public double calcTax() {
        double taxes = 0;
        if (this.grossIncome < 30000) {
            taxes = this.grossIncome * 0.05;
        } else {
            taxes = this.grossIncome * 0.06;
        }

        return taxes;
    }

}

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



Τώρα, μέσα στο ίδιο πακέτο που βρίσκεται και η κλάση Taxes, δημιουργούμε μια ακόμα κλάση με το όνομα Employee που και αυτή θα περιέχει τις δικές της instance μεταβλητές και μεθόδους. Όμως, επειδή θα χρειαστεί η κλάση Employee να χρησιμοποιήσει πληροφορίες της κλάσης Taxes, ορίζουμε μια μεταβλητή tax είδος Taxes μέσα στην Employee. Με άλλα λόγια μια από τις μεταβλητές της Employee είναι ένα reference σε ένα άλλο αντικείμενο.

Employee.java

package com.example;

public class Employee {
    public String name;
    public int employeeId;
    public String department;
    public int remainingDays;
    public Taxes tax;
}

Επειδή όμως δεν μας αρέσει να έχουμε public τις instance variables, ας τις αλλάξουμε σε private και ας προσθέσουμε τις getter και setter μεθόδους.

Employee.java

package com.example;

public class Employee {
    private String name;
    private int employeeId;
    private String department;
    private int remainingDays;
    private Taxes tax;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getEmployeeId() {
        return this.employeeId;
    }

    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }

    public String getDepartment() {
        return this.department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public int getRemainingDays() {
        return this.remainingDays;
    }

    public void setRemainingDays(int remainingDays) {
        this.remainingDays = remainingDays;
    }

    public Taxes getTax() {
        return this.tax;
    }

    public void setTax(Taxes tax) {
        this.tax = tax;
    }

}

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

Employee.java

package com.example;

public class Employee {
    private String name;
    private int employeeId;
    private String department;
    private int remainingDays;
    private Taxes tax;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getEmployeeId() {
        return this.employeeId;
    }

    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }

    public String getDepartment() {
        return this.department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public int getRemainingDays() {
        return this.remainingDays;
    }

    public void setRemainingDays(int remainingDays) {
        this.remainingDays = remainingDays;
    }

    public Taxes getTax() {
        return this.tax;
    }

    public void setTax(Taxes tax) {
        this.tax = tax;
    }

    public void mailCheck() {
        System.out.println("Mailing a tax report to " + this.name);
        System.out.println("Your final income after taxes is: " + tax.calcTax());
    }

    public void vacationCalc(int daysTotal, int daysRequested) {
        this.remainingDays = daysTotal - daysRequested;
        System.out.println("You have requested " + daysRequested + " days of vacation");
    }

}

Ας ολοκληρώσουμε το πρόγραμμα μας, αναβαθμίζοντας το κώδικα της κλάσης App μέσα από την οποία δημιουργούμε κάποια αντικείμενα και τυπώνουμε το αποτέλεσμα στο terminal.

App.java

package com.example;

public class App {
    public static void main(String[] args) {
        Employee michail = new Employee();
        Taxes tax = new Taxes(30000, 2);
        michail.setTax(tax);
        michail.setName("Michail Kassapoglou");
        michail.mailCheck();
        michail.vacationCalc(22, 5);
        System.out.println("You still have " + michail.getRemainingDays() + " of vacation days left");
    }
}

Output

Mailing a tax report to Michail Kassapoglou

Your final income after taxes is: 1800.0

You have requested 5 days of vacation

You still have 17 of vacation days left

Αν κοιτάξετε την δομή του project σας, θα παρατηρήσετε ότι όλες οι κλάσεις έχουν δημιουργηθεί μέσα στο ίδιο πακέτο που ονομάζετε com.example. Όπως ήδη έχουμε αναφέρει στα αρχικά δωρεάν μαθήματα Java, ένα πακέτο πρακτικά δεν είναι τίποτα άλλο από ένας φάκελος στο σκληρό δίσκο μέσα στον οποίο ομαδοποιούμε τις κλάσεις μας.

Δωρεάν μαθήματα Java

Κάθε φορά που δημιουργούμε μια κλάση μέσα στο com.example πακέτο, η Java τοποθετεί το όνομα του πακέτου πριν τον ορισμό της κλάσης. Όταν λοιπόν από την κλάση App.java δημιουργήσαμε ένα αντικείμενο που ανήκει στην κλάση Taxes ή Employee, επειδή όλες οι κλάσεις ανήκουν στο ίδιο πακέτο, η Java μπορούσε εύκολα να τις βρει και να δημιουργήσει τα αντικείμενα. Το πακέτο στο οποίο ανήκει η App.java από την οποία δημιουργούμε αντικείμενα, γίνεται το default πακέτο στο οποίο θα ψάξει τις υπόλοιπες κλάσεις o compiler της Java.




Όμως αν το πρόγραμμα μας συνεχίζει να μεγαλώνει, τότε δεν θα μπορούμε εύκολα να διακρίνουμε ποια κλάση κάνει τι. Για παράδειγμα, αν προσθέσουμε κλάσεις οι οποίες είναι υπεύθυνες για το γραφικό σκέλος (UI) της εφαρμογής, κλάσεις οι οποίες στέλνουν email, και κλάσεις που έχουν αναλάβει την επικοινωνία με την βάση, τότε το project μας θα έχει μια μεγάλη λίστα από κλάσεις που δεν θα είναι ομαδοποιημένες κατά functionality και θα είναι χρονοβόρο για τον προγραμματιστή να βρεις ποιες κλάσεις συνδέονται μεταξύ τους για μια κοινή λειτουργία.

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

Κάνουμε λοιπόν δεξί κλικ επάνω στο πακέτο example και από το εμφανιζόμενο μενού επιλέγουμε New Folder. Γράψτε το όνομα greektaxes και πατήστε Enter να δημιουργηθεί το καινούργιο package.

Τώρα κάντε drag-and-drop (μετακινήστε) το αρχείο Taxes μέσα στο φάκελο greektaxes. Το τελικό αποτέλεσμα πρέπει να είναι παρόμοιο με την παρακάτω εικόνα. Παρατηρήστε ότι ο ορισμός του πακέτου για την κλάση Taxes άλλαξε αφού τώρα ανήκει σε άλλο πακέτο.




Τώρα όμως το πρόγραμμα μας παρουσιάζει σημάδια λάθους. Και αυτό συμβαίνει και με τη κλάση Employee και με τη κλάση App. Στην ουσία αυτές οι δύο κλάσεις δεν γνωρίζουν που βρίσκεται η κλάση Taxes για να την χρησιμοποιήσουν. 



Εδώ λοιπόν η Java μας προσφέρει μια εντολή που ονομάζεται import για να μπορέσουμε να δηλώσουμε στο κώδικα μας που βρίσκονται άλλες κλάσεις ή βιβλιοθήκες (Libraries) που τυχόν χρειαζόμαστε. Η διαδικασία δήλωσης μιας κλάσης γίνεται ακόμα ευκολότερη με τα σημερινά IDE γιατί σου προτείνουν πώς να διορθωθεί το πρόβλημα.

Αν πάμε πίσω στην κλάση Employee και περάσουμε το ποντίκι επάνω από την μεταβλητή Taxes, το VS Code θα μας προτείνει μια λύση αφού πατήσουμε επάνω στην επιλογή Quick Fix.



Πατώντας επάνω στην επιλογή Import Taxes, αυτόματα η εντολή import θα δηλώσει τη σωστή τοποθεσία της κλάσης Taxes στην κλάση Employee και το λάθος θα εξαλειφτεί.


Με τη λέξη import λοιπόν δηλώνουμε στην κλάση μας σε ποια πακέτα βρίσκονται άλλες κλάσεις που χρειαζόμαστε για την δημιουργία αντικειμένων. Τις περισσότερες φορές το ίδιο το IDE θα σας προτείνει τη σωστή λύση.

Η εντολή import πάντα ορίζεται μετά από την εντολή package. Πρώτα λοιπόν δηλώνουμε σε ποιο πακέτο ανήκει η κλάση μας, και μετά δηλώνουμε ποιες άλλες κλάσεις θέλουμε να χρησιμοποιήσουμε. Επίσης αν υπάρχουν πολλαπλές κλάσεις μέσα σε ένα πακέτο, αντί να κάνετε import μια προς μια τις κλάσεις, μπορείτε απλά να δηλώσετε με * ότι θέλετε να κάνετε Import όλες τις κλάσεις από το συγκεκριμένο πακέτο.


Ας διορθώσουμε επίσης το import και στην κλάση App και εκτελέστε το πρόγραμμα ξανά, για να βεβαιωθείτε  ότι όλα παίζουν κανονικά πάλι.


Πριν κλείσουμε το σημερινό πρώτο μέρος του δωρεάν μαθήματος Java, θα ήθελα να κάνουμε μια γρήγορη αναφορά στην κλάση String και στην κλάση System. Καλούμε αυτές τις δύο κλάσεις μέσα στο πρόγραμμα μας χωρίς να κάνουμε κάποιο ιδιαίτερο  import. Ο λόγος είναι ότι η Java, για κάθε κλάση που δημιουργούμε, κάνει import το πακέτο java.lang.* αυτόματα στη κλάση μας. Μπορούμε επίσης αντί να δηλώσουμε το import πριν το ορισμό της κλάσης, να το κάνουμε μέσα στο κώδικα μας, αν θέλουμε να χρησιμοποιήσουμε μόνο μια φορά κάποια κλάση. Αυτός ο τρόπος δεν είναι και πολύ βολικός για αυτό άλλωστε δεν θα το συναντήσετε σχεδόν καθόλου σε καθημερινό κώδικα.


Κάπου εδώ θα κλείσουμε το πρώτο μέρος της αναφοράς μας στα packages και στα access specifiers. Στο επόμενο δωρεάν μάθημα Java θα τα συνδυάσουμε και τα δύο για να δημιουργήσουμε μια εξωτερική βιβλιοθήκη που θα την κάνουμε import στο project μας.

Μην ξεχάσετε να κάνετε ένα μικρό donation έτσι ώστε αυτό το blog να μεγαλώσει ακόμα πιο πολύ και να έχει περισσότερες δυνατότητες στην online παράδοση δωρεάν μαθημάτων.

full-width

Post a Comment

0 Comments