Μοτίβο σχεδίασης εργοστασίων | Java Development Journal

0
Μοτίβο σχεδίασης εργοστασίων |  Java Development Journal

Σε αυτό το άρθρο της σειράς μοτίβων σχεδίασης, θα συνεχίσουμε να μαθαίνουμε τα μοτίβα σχεδίασης και θα καλύψουμε τα Μοτίβο σχεδίασης εργοστασίων σε Java. Θα ρίξουμε μια ματιά στις διαφορετικές χρήσεις του εργοστασιακού μοτίβου σχεδιασμού και πώς να το εφαρμόσουμε στην Java.

1. Μοτίβο σχεδίασης εργοστασίων

Το σχέδιο Factory είναι ένα από τα μοτίβα δημιουργίας και μπορούμε να βρούμε τις χρήσεις του σχεδόν σε όλες τις βιβλιοθήκες στο JDK, Spring. Θα καταλάβουμε τι σημαίνει αυτό το μοτίβο για τη χρήση μιας εφαρμογής Java. Στη συνέχεια θα δούμε τα πλεονεκτήματα σχεδιασμού αυτού του μοτίβου. Αυτό το εργοστασιακό μοτίβο σχεδίασης παρέχει μια διεπαφή για τη δημιουργία αντικειμένων σε μια υπερ-κλάση, αλλά επιτρέπει στις υπο-κλάσεις να αλλάζουν τον τύπο των αντικειμένων που θα δημιουργηθούν.

Το μοτίβο σχεδίασης Factory ή το μοτίβο σχεδίασης Factory Method ταιριάζει καλύτερα στην περίπτωση όπου μια υπερ-κλάση (Interface, Abstract Class ή non-final Classes) έχει πολλαπλές υποκατηγορίες (υλοποιήσεις) και κατά το χρόνο εκτέλεσης επιλέγουμε την ακριβή εφαρμογή τάξη με βάση την είσοδο. Το Factory θα είναι υπεύθυνο για τη δημιουργία και τη δημιουργία της κλάσης υλοποίησης και την παροχή της στο πρόγραμμα πελάτη. Το εργοστασιακό μοτίβο χρησιμοποιεί αντανακλάσεις εσωτερικά για να δημιουργήσει τις κλάσεις και δεν χρησιμοποιεί νέος απευθείας χειριστή.

1.1. Δήλωση προβλήματος

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

  • Τρεχούμενος λογαριασμός
  • Επαγγελματικός λογαριασμός
  • ΠΡΟΣΩΠΙΚΟΣ ΛΟΓΑΡΙΑΣΜΟΣ

Πώς θα χειριστείτε αυτήν την κατάσταση όπου επικεντρώνεστε σε μια συγκεκριμένη περίπτωση αλλά έχετε σχέδιο να κυκλοφορήσετε νέες παραλλαγές στο μέλλον;

1.2. Λύση

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

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

2. Factory Design Pattern σε Java

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

Θέλουμε επίσης να διατηρήσουμε τη δυνατότητα προσφοράς άλλου τύπου λογαριασμού στο μέλλον. Λάβετε επίσης υπόψη ότι κάθε τύπος λογαριασμού θα έχει τον δικό του κανόνα και τις δικές του διαδικασίες και δεν μπορούμε να έχουμε μία κλάση που να χειρίζεται όλους τους τύπους λογαριασμών. Έτσι το UML ή το διάγραμμα ροής μοιάζει να χρησιμοποιείται το εργοστασιακό μας σχέδιο σχεδιασμού

Μοτίβο σχεδίασης εργοστασίων
Μοτίβο σχεδίασης εργοστασίων

Διαφημίσεις

Ας δούμε την εφαρμογή του σε Java

2.1. Superclass

Όπως αναφέρθηκε παραπάνω, η υπερκλάση στο μοτίβο σχεδίασης Factory μπορεί να είναι διεπαφές, αφηρημένες κλάσεις ή μη τελικές κλάσεις. Ας πάρουμε ένα παράδειγμα τραπεζικών λογαριασμών όπως Προσωπικός, Επιχείρησηκαι Ελεγχος και χρησιμοποιήστε το BankAccountFactory για να δημιουργήσετε αυτούς τους λογαριασμούς σύμφωνα με τις απαιτήσεις του πελάτη. Θα δούμε πρώτα την superclass που στην περίπτωσή μας είναι μια διεπαφή BankAccountαυτή η διεπαφή θα έχει μία μόνο μέθοδο registerAccount().

public interface BankAccount {
    public void registerAccount();
}

2.2 Υποκατηγορίες

Για το παράδειγμά μας έχουμε 3 κλάσεις υλοποίησης που θα υλοποιήσουν το BankAccount διεπαφή, παρακάτω είναι κώδικας για το ίδιο, παρατηρήστε ότι θα έχουν τον τρόπο τους να το εφαρμόσουν registerAccount() μέθοδος.

ΠΡΟΣΩΠΙΚΟΣ ΛΟΓΑΡΙΑΣΜΟΣ

public class PersonalAccount implements BankAccount {
    @Override
    public void registerAccount() {
        System.out.println("Creating a personal account");
    }
}

Επαγγελματικός λογαριασμός

public class BusinessAccount implements BankAccount {
    @Override
    public void registerAccount() {
        System.out.println("Creating a business account");
    }
}

Τρεχούμενος λογαριασμός

public class CheckingAccount implements BankAccount {
    @Override
    public void registerAccount() {
        System.out.println("Creating a checking account");
    }
}

Μην δίνετε μεγάλη σημασία στη λογική μέσα σε αυτές τις τάξεις, καθώς αυτή θα βασίζεται στις απαιτήσεις σας. Λάβετε υπόψη ότι κάθε κλάση παρακάμπτει το registerAccount() μέθοδο που είναι το κλειδί για την περίπτωση χρήσης μας.

2.3. Εργοστασιακή Κατηγορία

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

public class BankAccountFactory {
    public BankAccount createAccount(String type) {
        BankAccount bankAccount = null;
        if (type.equals("P")) {
            bankAccount = new PersonalAccount();
        } else if (type.equals("B")) {
            bankAccount = new BusinessAccount();
        } else if (type.equals("C")) {
            bankAccount = new CheckingAccount();
        } else {
            System.out.println("Invalid type");
        }
        return bankAccount;
    }
}

ο registerAccount() Η μέθοδος στον παραπάνω κώδικα είναι εργοστασιακή, λαμβάνει είσοδο από τον καλούντα και με βάση αυτήν την τιμή εισόδου δημιουργεί την αντίστοιχη κλάση υλοποίησης, σε περίπτωση που η δεδομένη είσοδος είναι άκυρη, θα επιστρέψουμε ένα „invalid typeμήνυμα ή μπορούμε επίσης να κάνουμε μια εξαίρεση.

Διαφημίσεις

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

public class Branch {
    public static void main(String[] args) {
        BankAccount bankAccount = null;
        BankAccountFactory bankAccountFactory = new BankAccountFactory();
        Scanner in = new Scanner(System.in);
        System.out.println("Please enter\n" +
            " P for Personal account\n" +
            " B for Business account\n" +
            " C for Checking account\n" +
            "----------------------------");
        String accountType = in .nextLine();
        bankAccount = bankAccountFactory.createAccount(accountType);
        bankAccount.registerAccount();;
    }
}

Αν τρέξουμε τον κώδικα μας, θα έχουμε την εξής έξοδο:

Please enter
 P for Personal account
 B for Business account
 C for Checking account
----------------------------
P
Creating a personal account


Please enter
 P for Personal account
 B for Business account
 C for Checking account
----------------------------
B
Creating a business account


Please enter
 P for Personal account
 B for Business account
 C for Checking account
----------------------------
C
Creating a checking account

Εδώ είναι η πλήρης περίπτωση δοκιμής:

Διαφημίσεις

package com.javadevjournal.designpatterns.factory;

import com.javadevjournal.designpatterns.factory.account.BankAccount;
import com.javadevjournal.designpatterns.factory.account.BusinessAccount;
import com.javadevjournal.designpatterns.factory.account.CheckingAccount;
import com.javadevjournal.designpatterns.factory.account.PersonalAccount;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;


public class FactoryDesignPatternTest {


    private BankAccountFactory factory;

    @Before
    public void setUp() {
        factory = new BankAccountFactory();
    }

    @Test
    public void testPersonalAccount() {
        BankAccount account = factory.createAccount("P");
        assertThat(account, instanceOf(PersonalAccount.class));
    }

    @Test
    public void testBusinessAccount() {
        BankAccount account = factory.createAccount("B");
        assertThat(account, instanceOf(BusinessAccount.class));
    }

    @Test
    public void testCheckingAccount() {
        BankAccount account = factory.createAccount("C");
        assertThat(account, instanceOf(CheckingAccount.class));
    }

    @Test
    public void testValidAccountType() {
        BankAccount account = factory.createAccount("X");
        assertNull(account);
    }
}

Δείτε πώς φαίνεται το συνολικό διάγραμμα τάξης:

Μοτίβο σχεδίασης εργοστασίων σε Java

3. Πότε να χρησιμοποιήσετε το Factory Design Pattern

  1. Μπορούμε να χρησιμοποιήσουμε το εργοστασιακό μοτίβο σχεδιασμού όταν δεν γνωρίζουμε τον τύπο εκ των προτέρων. Στο παράδειγμά μας, δεν γνωρίζουμε τον τύπο λογαριασμού που μπορεί να επιλέξει ο πελάτης στην τράπεζά μας. Δημιουργούμε τον τύπο λογαριασμού κατά τον χρόνο εκτέλεσης με βάση τα στοιχεία των πελατών.
  2. Όταν θέλουμε να επεκτείνουμε τον κώδικα για να υποστηρίξουμε περισσότερη εφαρμογή στο μέλλον. Μπορούμε πάντα να εκκινήσουμε νέο τύπο λογαριασμού στο μέλλον προσθέτοντας έναν μικρότερο κωδικό στην εργοστασιακή κατηγορία χωρίς να αγγίξουμε κανέναν άλλο κωδικό.
  3. Όταν θέλουμε να επαναχρησιμοποιήσουμε τα ίδια αντικείμενα στους ίδιους πόρους του συστήματος.
  4. Το εργοστασιακό σχέδιο σχεδίασης μας βοηθά να διαχωρίσουμε τον κώδικα δημιουργίας αντικειμένου από αυτόν που τον χρησιμοποιεί.
  5. Μπορούμε να χρησιμοποιήσουμε τη μέθοδο Factory όταν θέλουμε να παρέχουμε στους χρήστες της βιβλιοθήκης μας έναν τρόπο να επεκτείνουν τα εσωτερικά της στοιχεία.

4. Πλεονεκτήματα του Factory Design Pattern

  1. Το εργοστασιακό σχέδιο σχεδίασης αφαιρεί την πραγματική έναρξη κλάσης από τις κλάσεις πελάτη. Άρα, είναι ξεκάθαρη αφαίρεση περίπτωσης χρήσης.
  2. Η εργοστασιακή μέθοδος υποστηρίζει τις αρχές SOLID και επιτρέπει στους προγραμματιστές να κωδικοποιούν για διεπαφή αντί για υλοποίηση.
  3. Διασφαλίζει ότι η προσθήκη νέας υλοποίησης είναι εξαιρετικά εύκολη και μπορούμε πολύ εύκολα να προσθέσουμε ένα άλλο σχήμα όπως το πεντάγωνο και να προσθέσουμε μερικές γραμμές στον εργοστασιακό κώδικα για να το υποστηρίξουμε.
  4. Το σχέδιο σχεδίασης καθιστά ολόκληρο τον κώδικα επεκτάσιμο και έτοιμο για το μέλλον.
  5. Το εργοστασιακό σχέδιο σχεδίασης κάνει τον κώδικα εξαιρετικά συνεκτικό και λιγότερο συνδεδεμένο.

Λάβετε υπόψη ότι θα προσθέσει κάποια πολυπλοκότητα στη βάση του κώδικά μας, πρέπει να εφαρμόσουμε μια νέα υποκατηγορία για κάθε νέο τύπο λογαριασμού (Αλλά αυτό είναι καλό για τη μακροπρόθεσμη συντήρηση και τη συντήρηση του κώδικα 🙂 )

5. Παράδειγμα σε JDK και Spring

Ακολουθούν μερικά παραδείγματα όπου αυτό χρησιμοποιείται JDK και Εαρινό Πλαίσιο.

  1. Εαρινό Πλαίσιο BeanFactory
  2. Εαρινό Πλαίσιο ApplicationContext
  3. java.util.Calendar#getInstance()
  4. java.text.NumberFormat#getInstance()
  5. java.util.EnumSet#of()
  6. java.util.Collection#Iterator

Περίληψη

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

Schreibe einen Kommentar