JavaRush /בלוג Java /Random-HE /דפוסי עיצוב: AbstractFactory

דפוסי עיצוב: AbstractFactory

פורסם בקבוצה
שלום! היום נמשיך ללמוד דפוסי עיצוב ונדבר על המפעל המופשט . דפוסי עיצוב: AbstractFactory - 1מה נעשה במהלך ההרצאה:
  • בואו נדון מהו מפעל מופשט ואיזו בעיה דפוס זה פותר;
  • ניצור מסגרת של אפליקציה חוצת פלטפורמות להזמנת קפה עם ממשק משתמש;
  • בואו נלמד את ההוראות לשימוש בדפוס זה עם תרשים וקוד;
  • כבונוס, בהרצאה מסתתרת ביצת פסחא שבזכותה תלמדו לקבוע את שם מערכת ההפעלה באמצעות Java ובהתאם לתוצאה לבצע פעולה כזו או אחרת.
כדי להבין את הדפוס הזה במלואו, עליך להבין היטב את הנושאים הבאים:
  • ירושה בג'אווה;
  • מחלקות ושיטות מופשטות ב-Java.

אילו בעיות פותרת תבנית המפעל המופשטת?

המפעל המופשט, כמו כל דפוסי המפעל, עוזר לנו לארגן את היצירה של חפצים חדשים בצורה נכונה. בעזרתו אנו מנהלים את "שחרור" של משפחות שונות של חפצים מחוברים. משפחות שונות של חפצים הקשורים זה בזה...מה זה? אל דאגה: בפועל הכל פשוט יותר ממה שזה נראה. נתחיל במה שיכולה להיות משפחה של חפצים קשורים? נניח שאנחנו מפתחים איתך אסטרטגיה, ויש בה כמה יחידות קרביות:
  • חֵיל הַרַגלִים;
  • חֵיל הַפָּרָשִׁים;
  • קשתים.
סוגים אלו של יחידות קרביות קשורות זו לזו, מכיוון שהן משרתות באותו צבא. אנו יכולים לומר שהקטגוריות המפורטות לעיל הן משפחה של עצמים הקשורים זה בזה. זה סודר. אבל תבנית המפעל המופשטת משמשת לארגון היצירה של משפחות שונות של אובייקטים מחוברים זה לזה. גם כאן שום דבר לא מסובך. בואו נמשיך את הדוגמה עם האסטרטגיה. בדרך כלל יש להם כמה צדדים מנוגדים שונים. יחידות הקרב של צדדים שונים עשויים להיות שונים באופן משמעותי במראה החיצוני. החיילים הרגליים, הפרשים והקשתים של הצבא הרומי אינם זהים לחיילי הרגליים, הפרשים והקשתים של הוויקינגים. במסגרת האסטרטגיה, חיילי צבאות שונים הם משפחות שונות של חפצים הקשורים זה בזה. זה יהיה מצחיק אם בטעות של מתכנת, חייל במדים צרפתיים מתקופת נפוליאון, עם מוסקט מוכן, היה מסתובב בין חיל הרגלים הרומי. זה כדי לפתור בעיה כזו שיש צורך בתבנית העיצוב המופשטת של המפעל. לא, לא הבעיות של מבוכה במסע בזמן, אלא יצירה של קבוצות שונות של אובייקטים מחוברים. מפעל אבסטרקט מספק ממשק ליצירת כל המוצרים הקיימים (חפצי משפחה). למפעל מופשט יש בדרך כלל יישומים מרובים. כל אחד מהם אחראי ליצירת מוצרים של אחת הווריאציות. כחלק מהאסטרטגיה, יהיה לנו מפעל מופשט שיוצר חיל רגלים מופשט, קשתים ופרשים, וכן יישומים של מפעל זה. מפעל שיוצר לגיונרים רומיים ולמשל מפעל שיוצר לוחמים קרתגים. הפשטה היא העיקרון החשוב ביותר של דפוס זה. לקוחות המפעל עובדים איתה ועם מוצרים רק באמצעות ממשקים מופשטים. לכן, אנחנו לא צריכים לחשוב איזה סוג של לוחמים אנחנו יוצרים כרגע, אלא להעביר את האחריות הזו ליישום ספציפי כלשהו של המפעל המופשט.

אנחנו ממשיכים להפוך את בית הקפה לאוטומטי

בהרצאה האחרונה למדנו את תבנית שיטת המפעל, בעזרתה הצלחנו להרחיב את עסקי הקפה ולפתוח מספר נקודות מכירה חדשות של קפה. היום נמשיך בעבודתנו למודרניזציה של העסק שלנו. באמצעות תבנית המפעל המופשטת, נניח את הבסיס ליישום שולחן עבודה חדש להזמנת קפה באינטרנט. כאשר אנו כותבים אפליקציה לשולחן העבודה, עלינו תמיד לחשוב על פלטפורמות שונות. האפליקציה שלנו אמורה לעבוד גם ב-macOS וגם ב-Windows (ספוילר: לינוקס ישאר לך כשיעורי בית). איך תיראה האפליקציה שלנו? די פשוט: זה יהיה טופס שמורכב משדה טקסט, שדה בחירה וכפתור. אם יש לך ניסיון בשימוש במערכות הפעלה שונות, בהחלט שמת לב שב-Windows הלחצנים מוצגים בצורה שונה מאשר ב-Mac. כמו כל דבר אחר... אז, בואו נתחיל. בתפקיד של משפחות מוצרים, כפי שבטח כבר הבנתם, יהיו לנו אלמנטים של ממשק גרפי:
  • כפתורים;
  • שדות טקסט;
  • שדות לבחירה.
כתב ויתור. בתוך כל ממשק נוכל להגדיר שיטות כמו onClick, onValueChangedאו onInputChanged. הָהֵן. שיטות שיאפשרו לנו לטפל באירועים שונים (לחיצה על כפתור, הזנת טקסט, בחירת ערך בתיבת בחירה). כל זה מושמט בכוונה כדי לא להעמיס על הדוגמה ולהפוך אותה חזותית יותר ללימוד דפוס המפעל. בואו נגדיר ממשקים מופשטים עבור המוצרים שלנו:
public interface Button {}
public interface Select {}
public interface TextField {}
עבור כל מערכת הפעלה, עלינו ליצור רכיבי ממשק בסגנון של אותה מערכת הפעלה. אנו כותבים עבור Windows ו- MacOS. בואו ניצור יישומים עבור Windows:
public class WindowsButton implements Button {
}

public class WindowsSelect implements Select {
}

public class WindowsTextField implements TextField {
}
עכשיו אותו דבר עבור MacOS:
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
גדול. כעת נוכל להתחיל את המפעל המופשט שלנו, שייצור את כל סוגי המוצרים המופשטים הקיימים:
public interface GUIFactory {

    Button createButton();
    TextField createTextField();
    Select createSelect();

}
מושלם. כפי שאתה יכול לראות, שום דבר לא מסובך עד כה. ואז הכל פשוט באותה מידה. באנלוגיה למוצרים, אנו יוצרים יישומים שונים של המפעל שלנו עבור כל מערכת הפעלה. נתחיל עם Windows:
public class WindowsGUIFactory implements GUIFactory {
    public WindowsGUIFactory() {
        System.out.println("Creating gui factory for Windows OS");
    }

    public Button createButton() {
        System.out.println("Creating Button for Windows OS");
        return new WindowsButton();
    }

    public TextField createTextField() {
        System.out.println("Creating TextField for Windows OS");
        return new WindowsTextField();
    }

    public Select createSelect() {
        System.out.println("Creating Select for Windows OS");
        return new WindowsSelect();
    }
}
פלט מסוף בתוך שיטות ובנאים נוספה כדי להדגים עוד יותר כיצד זה עובד. עכשיו עבור macOS:
public class MacGUIFactory implements GUIFactory {
    public MacGUIFactory() {
        System.out.println("Creating gui factory for macOS");
    }

    @Override
    public Button createButton() {
        System.out.println("Creating Button for macOS");
        return new MacButton();
    }

    @Override
    public TextField createTextField() {
        System.out.println("Creating TextField for macOS");
        return new MacTextField();
    }

    @Override
    public Select createSelect() {
        System.out.println("Creating Select for macOS");
        return new MacSelect();
    }
}
הערה: כל שיטה, לפי החתימה שלה, מחזירה טיפוס מופשט. אבל בתוך השיטה אנחנו יוצרים יישום קונקרטי של המוצר. זהו המקום היחיד שבו אנו שולטים ביצירת מופעים ספציפיים. עכשיו הגיע הזמן לכתוב את כיתת הטופס. זוהי מחלקת Java שהשדות שלה הם רכיבי ממשק:
public class OrderCoffeeForm {
    private final TextField customerNameTextField;
    private final Select coffeTypeSelect;
    private final Button orderButton;

    public OrderCoffeeForm(GUIFactory factory) {
        System.out.println("Creating order coffee form");
        customerNameTextField = factory.createTextField();
        coffeTypeSelect = factory.createSelect();
        orderButton = factory.createButton();
    }
}
מפעל מופשט מועבר לבונה הטופס, שיוצר רכיבי ממשק. נעביר את היישום המפעל הנדרש לבנאי כדי שנוכל ליצור רכיבי ממשק עבור מערכת הפעלה מסוימת.
public class Application {
    private OrderCoffeeForm orderCoffeeForm;

    public void drawOrderCoffeeForm() {
        // Определим Name операционной системы, получив meaning системной проперти через System.getProperty
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // Для windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // Для mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS, can't draw form :( ");
            return;
        }
        orderCoffeeForm = new OrderCoffeeForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawOrderCoffeeForm();
    }
}
אם נריץ את האפליקציה ב-Windows, נקבל את הפלט הבא:

Creating gui factory for Windows OS
Creating order coffee form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
ב-Mac הפלט יהיה כדלקמן:

Creating gui factory for macOS
Creating order coffee form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
על לינוקס:

Unknown OS, can't draw form :( 
ובכן, אתה ואני מסיקים את המסקנה הבאה. כתבנו מסגרת לאפליקציית GUI שיוצרת בדיוק את אותם רכיבי ממשק שמתאימים למערכת הפעלה נתונה. בואו נחזור בקצרה על מה שיצרנו:
  • משפחת מוצרים: שדה קלט, שדה בחירה וכפתור.
  • הטמעות שונות של משפחת מוצרים זו, עבור Windows ו-macOS.
  • מפעל מופשט, שבתוכו הגדרנו את הממשק ליצירת המוצרים שלנו.
  • שני יישומים של המפעל שלנו, שכל אחד מהם אחראי ליצירת משפחה ספציפית של מוצרים.
  • טופס, מחלקת Java שהשדות שלה הם רכיבי ממשק מופשטים שמאוחלים בקונסטרוקטור עם הערכים הנדרשים באמצעות מפעל מופשט.
  • שיעור יישום. בתוכו, אנו יוצרים טופס שבעזרתו אנו מעבירים את היישום הנדרש של המפעל שלנו לבנאי.
סך הכל: יישמנו את תבנית המפעל המופשטת.

מפעל מופשט: הוראות שימוש

מפעל מופשט הוא דפוס עיצובי לניהול יצירת משפחות מוצרים שונות מבלי להיות קשור למחלקות מוצרים ספציפיים. בעת שימוש בתבנית זו, עליך:
  1. הגדירו את משפחות המוצרים עצמם. נניח שיש לנו שניים מהם:
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. לכל מוצר בתוך המשפחה, הגדירו מחלקה מופשטת (ממשק). במקרה שלנו זה:
    • ProductA
    • ProductB
  3. בתוך כל משפחת מוצרים, כל מוצר חייב ליישם את הממשק שהוגדר בשלב 2.
  4. צור מפעל מופשט, עם שיטות יצירה לכל מוצר שהוגדרו בשלב 2. במקרה שלנו, שיטות אלו יהיו:
    • ProductA createProductA();
    • ProductB createProductB();
  5. צור יישומים של המפעל המופשט כך שכל יישום שולט ביצירת מוצרים מאותה משפחה. לשם כך, בתוך כל יישום של המפעל המופשט, יש צורך ליישם את כל שיטות היצירה, כך שיישומים קונקרטיים של מוצרים נוצרים ומוחזרים בתוכם.
להלן תרשים UML הממחיש את ההוראות שתוארו לעיל: דפוסי עיצוב: AbstractFactory - 3כעת נכתוב את הקוד להוראה זו:
// Определим общие интерфейсы продуктов
public interface ProductA {}
public interface ProductB {}

// Создадим различные реализации (семейства) наших продуктов
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}

public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}

// Создадим абстрактную фабрику
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory1 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB1();
    }
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory2 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB2();
    }
}

שיעורי בית

כדי לאחד את החומר אתה יכול לעשות 2 דברים:
  1. שפר את אפליקציית הזמנת הקפה כך שתעבוד על לינוקס.
  2. צור מפעל מופשט משלך לייצור יחידות מכל אסטרטגיה. זו יכולה להיות אסטרטגיה היסטורית עם צבאות אמיתיים או פנטזיה עם אורקים, גמדים ואלפים. העיקר שזה מעניין אותך. היו יצירתיים, פרסמו סיכות לקונסולה, ותהנו ללמוד את הדפוסים!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION