CodeGym /Java блог /Случаен /Модели на дизайн: Абстрактна фабрика
John Squirrels
Ниво
San Francisco

Модели на дизайн: Абстрактна фабрика

Публикувано в групата
здрасти Днес ще продължим да изучаваме дизайнерски модели и ще обсъдим абстрактния фабричен модел. Шаблони за дизайн: Абстрактна фабрика - 1Ето Howво ще разгледаме в урока:
  • Ще обсъдим Howво е абстрактна фабрика и Howъв проблем решава този модел
  • Ще създадем скелета на кросплатформено приложение за поръчка на кафе чрез потребителски интерфейс
  • Ще проучим инструкциите How да използваме този модел, включително да разгледаме диаграма и code
  • И като бонус, този урок включва скрито великденско яйце, което ще ви помогне да научите How да използвате Java, за да определите името на операционната система и в зависимост от резултата да извършите едно or друго действие.
За да разберете напълно този модел, трябва да сте добре запознати със следните теми:
  • наследяване в Java
  • абстрактни класове и методи в Java

Какви проблеми решава една абстрактна фабрика?

Абстрактната фабрика, Howто всички фабрични модели, ни помага да гарантираме, че новите обекти ще бъдат създадени правилно. Ние го използваме, за да управляваме "производството" на различни семейства от взаимосвързани обекти. Различни семейства от взаимосвързани обекти... Какво означава това? Не се притеснявайте: на практика всичко е по-просто, отколкото може да изглежда. Като начало, Howво може да бъде едно семейство от взаимосвързани обекти? Да предположим, че разработваме военна стратегия, включваща няколко вида единици:
  • пехота
  • кавалерия
  • стрелци с лък
Тези видове части са взаимосвързани, защото служат в една и съща армия. Можем да кажем, че изброените по-горе категории са семейство от взаимосвързани обекти. Ние разбираме това. Но абстрактният модел на фабриката се използва за организиране на създаването на различни семейства от взаимосвързани обекти. Тук също няма нищо сложно. Нека продължим с примера за военна стратегия. Най-общо казано, военните части принадлежат на няколко различни воюващи страни. В зависимост от това на чия страна са, военните единици могат значително да се различават по външен вид. Пехотинци, конници и стрелци на римската армия не са същите като викингските пешаци, конници и стрелци. Във военната стратегия войниците от различни армии са различни семейства от взаимосвързани обекти. Би било смешно, ако програмистът Тази грешка накара войник във френска униформа от епохата на Наполеон, с готов мускет, да бъде открит да върви сред редиците на римската пехота. Абстрактният модел на фабричен дизайн е необходим точно за решаването на този проблем. Не, не проблемът с неудобството, което може да дойде от пътуването във времето, а проблемът със създаването на различни групи от взаимосвързани обекти. Абстрактна фабрика предоставя интерфейс за създаване на всички налични продукти (семейство от обекти). Една абстрактна фабрика обикновено има множество реализации. Всеки от тях е отговорен за създаването на продукти на едно от семействата. Нашата военна стратегия ще включва абстрактна фабрика, която създава абстрактни пехотинци, стрелци и кавалеристи, Howто и реализации на тази фабрика. Например, фабрика, която създава римски легионери и фабрика, която създава картагенски войници. Абстракцията е най-важният ръководен принцип на този модел. Клиентите на фабриката работят с фабриката и нейните продукти само чрез абстрактни интерфейси. В резултат на това не е нужно да мислите кои войници се създават в момента. Вместо това прехвърляте тази отговорност на няHowво конкретно изпълнение на абстрактната фабрика.

Нека продължим да автоматизираме нашето кафене

В последния урок, проучихме модела на фабричния метод. Използвахме го, за да разширим бизнеса си с кафе и да отворим няколко нови локации. Днес ще продължим да модернизираме нашия бизнес. Използвайки абстрактния модел на фабриката, ние ще положим основата за ново десктоп приложение за онлайн поръчка на кафе. Когато пишем настолно приложение, винаги трябва да мислим за поддръжка на различни платформи. Нашето приложение трябва да работи Howто на macOS, така и на Windows (спойлер: Поддръжката за Linux е оставена за вас да внедрите като домашна работа). Как ще изглежда нашето приложение? Доста просто: това ще бъде формуляр, състоящ се от текстово поле, поле за избор и бутон. Ако имате опит с използването на различни операционни системи, със сигурност сте забелязали, че бутоните на Windows се изобразяват по различен начин, отколкото на Mac. Както и всичко останало... Е, да започваме.
  • бутони
  • текстови полета
  • полета за избор
Отказ от отговорност: Във всеки интерфейс можем да дефинираме методи като onClick, onValueChangedor onInputChanged. С други думи, можем да дефинираме методи, които ще ни позволят да обработваме различни събития (натискане на бутон, въвеждане на текст, избиране на стойност в поле за избор). Всичко това умишлено е пропуснато тук, за да не претоварим примера и да стане по-ясно, докато изучаваме фабричния модел. Нека дефинираме абстрактни интерфейси за нашите продукти:

public interface Button {}
public interface Select {}
public interface TextField {}
За всяка операционна система трябва да създадем интерфейсни елементи в стила на операционната система. Ще пишем code за 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();

}
Превъзходно. Както виждате, все още не сме направor нищо сложно. Всичко, което следва, също е просто. По аналогия с продуктите, ние създаваме различни фабрични реализации за всяка ОС. Да започнем с Windows:

public class WindowsGUIFactory implements GUIFactory {
    public WindowsGUIFactory() {
        System.out.println("Creating GUIFactory 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();
    }
}
Добавихме малко конзолен изход в методите и конструктора, за да илюстрираме допълнително Howво се случва. Сега за macOS:

public class MacGUIFactory implements GUIFactory {
    public MacGUIFactory() {
        System.out.println("Creating GUIFactory 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 CoffeeOrderForm {
    private final TextField customerNameTextField;
    private final Select coffeeTypeSelect;
    private final Button orderButton;

    public CoffeeOrderForm(GUIFactory factory) {
        System.out.println("Creating coffee order form");
        customerNameTextField = factory.createTextField();
        coffeeTypeSelect = factory.createSelect();
        orderButton = factory.createButton();
    }
}
Абстрактна фабрика, която създава интерфейсни елементи, се предава на конструктора на формуляра. Ние ще предадем необходимата фабрична имплементация на конструктора, за да създадем интерфейсни елементи за определена ОС.

public class Application {
    private CoffeeOrderForm coffeeOrderForm;

    public void drawCoffeeOrderForm() {
        // Determine the name of the operating system through System.getProperty()
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // For Windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // For Mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS. Unable to draw form :(");
            return;
        }
        coffeeOrderForm = new CoffeeOrderForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawCoffeeOrderForm();
    }
}
Ако стартираме приложението на Windows, получаваме следния резултат:

Creating GUIFactory for Windows OS
Creating coffee order form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
На Mac изходът ще бъде Howто следва:

Creating GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Под Linux:

Unknown OS. Unable to draw form :( 
И сега обобщаваме. Написахме скелета на GUI-базирано приложение, в което интерфейсните елементи са създадени специално за съответната ОС. Ще повторим сбито сътвореното от нас:
  • Семейство продукти, състоящо се от поле за въвеждане, поле за избор и бутон.
  • Различни реализации на фамorята продукти за Windows и macOS.
  • Абстрактна фабрика, която дефинира интерфейс за създаване на нашите продукти.
  • Две реализации на нашата фабрика, всяка от които отговаря за създаването на специфично семейство от продукти.
  • Форма (клас на Java), чиито полета са абстрактни интерфейсни елементи, които се инициализират с необходимите стойности в конструктора с помощта на абстрактна фабрика.
  • Клас на приложението Вътре в този клас ние създаваме форма, предавайки желаната фабрична реализация на нейния конструктор.
Резултатът е, че внедрихме абстрактния фабричен модел.

Абстрактна фабрика: How да се използва

Абстрактната фабрика е шаблон за проектиране за управление на създаването на различни фамorи продукти, без да се обвързва с конкретни класове продукти. Когато използвате този шаблон, трябва:
  1. Дефинирайте продуктови семейства. Да предположим, че имаме две от тях:
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. За всеки продукт в семейството дефинирайте абстрактен клас (интерфейс). В нашия случай имаме:
    • ProductA
    • ProductB
  3. В рамките на всяко продуктово семейство всеки продукт трябва да реализира интерфейса, дефиниран в стъпка 2.
  4. Създайте абстрактна фабрика с методи за създаване на всеки продукт, дефинирани в стъпка 2. В нашия случай тези методи ще бъдат:
    • ProductA createProductA();
    • ProductB createProductB();
  5. Създавайте абстрактни фабрични реализации, така че всяка реализация да контролира създаването на продукти от едно семейство. За да направите това, вътре във всяка реализация на абстрактната фабрика, трябва да внедрите всички методи за създаване, така че те да създават и връщат конкретни реализации на продукта.
Следващата UML диаграма илюстрира инструкциите, посочени по-горе: Шаблони за дизайн: Абстрактна фабрика - 3Сега ще напишем code според тези инструкции:

    // Define common product interfaces
    public interface ProductA {}
    public interface ProductB {}

    // Create various implementations (families) of our products
    public class SpecificProductA1 implements ProductA {}
    public class SpecificProductB1 implements ProductB {}

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

    // Create an abstract factory
    public interface AbstractFactory {
        ProductA createProductA();
        ProductB createProductB();
    }

    // Implement the abstract factory in order to create products in family 1
    public class SpecificFactory1 implements AbstractFactory {

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

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

    // Implement the abstract factory in order to create products in family 2
    public class SpecificFactory2 implements AbstractFactory {

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

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

Домашна работа

За да подсorте материала, можете да направите 2 неща:
  1. Усъвършенствайте приложението за поръчка на кафе, така че да работи и на Linux.
  2. Създайте своя собствена абстрактна фабрика за производство на единици, участващи във всяка военна стратегия. Това може да бъде or историческа военна стратегия, включваща реални армии, or фантастична стратегия с орки, гноми и елфи. Важното е да изберете нещо, което ви интересува. Бъдете креативни, отпечатвайте съобщения на конзолата и се наслаждавайте на изучаването на модели!
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION