Статьи

Пример абстрактного дизайна фабрики

Эта статья является частью нашего курса Академии под названием « Шаблоны проектирования Java» .

В этом курсе вы изучите огромное количество шаблонов проектирования и увидите, как они реализуются и используются в Java. Вы поймете причины, почему шаблоны так важны, и узнаете, когда и как применять каждый из них. Проверьте это здесь !

1. Введение

На предыдущем уроке мы разработали приложение для продуктовой компании для анализа XML и отображения результатов для них. Мы сделали это, создав разные парсеры для разных типов связи между компанией и ее клиентами. Мы использовали шаблон фабричного метода проектирования, чтобы решить их проблему.

Приложение работает нормально для них. Но теперь клиенты не хотят следовать специфике XML-правил компании. Клиенты хотят использовать свои собственные правила XML для связи с компанией-производителем. Это означает, что для каждого клиента у компании должны быть специфичные для клиента парсеры XML. Например, для клиента NY должно быть четыре конкретных типа анализаторов XML, то есть NYErrorXMLParser, NYFeedbackXML, NYOrderXMLParser, NYResponseXMLParser и четыре различных анализатора для клиента TW.

Компания попросила вас изменить приложение в соответствии с новым требованием. Для разработки приложения парсера мы использовали шаблон проектирования фабричных методов, в котором подклассы определяют точный объект для использования в соответствии с типом парсера. Теперь, чтобы реализовать это новое требование, мы будем использовать фабрику фабрик, то есть абстрактную фабрику.

На этот раз нам нужны синтаксические анализаторы в соответствии с конкретными XML-файлами клиента, поэтому мы создадим разные фабрики для разных клиентов, которые предоставят нам специфический для клиента XML для анализа. Мы сделаем это путем создания абстрактной фабрики, а затем реализуем фабрику, чтобы предоставить клиентскую фабрику XML Затем мы будем использовать эту фабрику для получения требуемого специфичного для клиента объекта XML-анализатора.

Абстрактная фабрика — это шаблон проектирования, который мы выбрали, и, прежде чем применять его для решения нашей проблемы, мы узнаем о нем больше.

2. Что такое абстрактный шаблон проектирования фабрики

Абстрактная фабрика (AKA Kit) — это шаблон проектирования, который предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов. Шаблон «Абстрактная фабрика» выводит концепцию «Шаблон фабричного метода» на следующий уровень. Абстрактная фабрика — это класс, который предоставляет интерфейс для создания семейства объектов. В Java это может быть реализовано с использованием интерфейса или абстрактного класса.

Шаблон Abstract Factory полезен, когда клиентский объект хочет создать экземпляр одного из набора связанных, зависимых классов, не зная, какой конкретный конкретный класс должен быть создан. Различные конкретные фабрики реализуют абстрактный интерфейс фабрики. Клиентские объекты используют эти конкретные фабрики для создания объектов и, следовательно, не должны знать, какой конкретный класс фактически создан.

Абстрактная фабрика полезна для подключения другой группы объектов для изменения поведения системы. Для каждой группы или семейства реализуется конкретная фабрика, которая управляет созданием объектов и требованиями взаимозависимостей и согласованности между ними. Каждый конкретный завод реализует интерфейс абстрактного завода

class_diagram_1

фигура 1

AbstractFactory

  • Объявляет интерфейс для операций, которые создают абстрактные объекты продукта.

ConcreteFactory

  • Реализует операции по созданию конкретных объектов товара.

AbstractProduct

  • Объявляет интерфейс для типа объекта продукта.

ConcreteProduct

  • Определяет объект продукта, который будет создан соответствующей бетонной фабрикой.
  • Реализует интерфейс AbstractProduct.

клиент

  • Используются только интерфейсы, объявленные классами AbstractFactory и AbstractProduct.

3. Реализация абстрактного шаблона проектирования фабрики

Для реализации шаблона проектирования абстрактной фабрики мы сначала создадим интерфейс, который будет реализован всеми конкретными фабриками.

1
2
3
4
5
6
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public interface AbstractParserFactory {
 
    public XMLParser getParserInstance(String parserType);
}

Вышеупомянутый интерфейс реализуется конкретными фабриками клиента, которые будут предоставлять объект синтаксического анализатора XML клиентскому объекту. Метод getParserInstance принимает parserType в качестве аргумента, который используется для получения объекта парсера, специфичного для сообщения (анализатор ошибок, анализатор заказов и т. Д.).

Два конкретных конкретных парсера фабрики:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class NYParserFactory implements AbstractParserFactory {
 
    @Override
    public XMLParser getParserInstance(String parserType) {
 
        switch(parserType){
            case "NYERROR": return new NYErrorXMLParser();
            case "NYFEEDBACK": return new NYFeedbackXMLParser ();
            case "NYORDER": return new NYOrderXMLParser();
            case "NYRESPONSE": return new NYResponseXMLParser();
        }
 
        return null;
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class TWParserFactory implements AbstractParserFactory {
 
    @Override
    public XMLParser getParserInstance(String parserType) {
 
        switch(parserType){
            case "TWERROR": return new TWErrorXMLParser();
            case "TWFEEDBACK": return new TWFeedbackXMLParser ();
            case "TWORDER": return new TWOrderXMLParser();
            case "TWRESPONSE": return new TWResponseXMLParser();
        }
 
        return null;
    }
 
}

Вышеуказанные две фабрики реализуют интерфейс AbstractParserFactory и переопределяют метод getParserInstance . Он возвращает специфичный для клиента объект парсера в соответствии с типом парсера, запрошенным в аргументе.

1
2
3
4
5
6
7
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public interface XMLParser {
 
    public String parse();
 
}

Приведенный выше интерфейс реализован конкретными классами синтаксического анализатора для синтаксического анализа XML и возвращает строковое сообщение.

Существует два клиента и четыре разных типа обмена сообщениями между компанией и ее клиентом. Таким образом, должно быть шесть различных типов конкретных анализаторов XML, специфичных для клиента.

01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class NYErrorXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("NY Parsing error XML...");
        return "NY Error XML Message";
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class NYFeedbackXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("NY Parsing feedback XML...");
        return "NY Feedback XML Message";
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class NYOrderXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("NY Parsing order XML...");
        return "NY Order XML Message";
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class NYResponseXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("NY Parsing response XML...");
        return "NY Response XML Message";
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class TWErrorXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("TW Parsing error XML...");
        return "TW Error XML Message";
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class TWFeedbackXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("TW Parsing feedback XML...");
        return "TW Feedback XML Message";
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class TWOrderXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("TW Parsing order XML...");
        return "TW Order XML Message";
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class TWResponseXMLParser implements XMLParser{
 
    @Override
    public String parse() {
        System.out.println("TW Parsing response XML...");
        return "TW Response XML Message";
    }
 
}

Чтобы избежать зависимости между клиентским кодом и фабриками, при желании мы реализовали фабричный производитель, который имеет статический метод и отвечает за предоставление требуемого фабричного объекта клиентскому объекту.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public final class ParserFactoryProducer {
 
    private ParserFactoryProducer(){
        throw new AssertionError();
    }
 
    public static AbstractParserFactory getFactory(String factoryType){
 
        switch(factoryType)
        {
            case "NYFactory": return new NYParserFactory();
            case "TWFactory": return new TWParserFactory();
        }
 
        return null;
    }
 
}

Теперь давайте проверим код.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package com.javacodegeeks.patterns.abstractfactorypattern;
 
public class TestAbstractFactoryPattern {
 
    public static void main(String[] args) {
 
        AbstractParserFactory parserFactory = ParserFactoryProducer.getFactory("NYFactory");
        XMLParser parser = parserFactory.getParserInstance("NYORDER");
        String msg="";
        msg = parser.parse();
        System.out.println(msg);
 
        System.out.println("************************************");
 
        parserFactory = ParserFactoryProducer.getFactory("TWFactory");
        parser = parserFactory.getParserInstance("TWFEEDBACK");
        msg = parser.parse();
        System.out.println(msg);
    }
 
}

Приведенный выше код приведет к следующему выводу:

1
2
3
4
5
NY Parsing order XML...
NY Order XML Message
************************************
TW Parsing feedback XML...
TW Feedback XML Message

В вышеприведенном классе мы сначала получили фабрику в Нью-Йорке от фабричного производителя, а затем парсер XML-заказов из фабрики парсеров в Нью-Йорке. Затем мы вызвали метод parse для объекта parser и отобразили возвращаемое сообщение. Мы сделали то же самое для клиента TW, как ясно показано в выводе.

4. Когда использовать абстрактный шаблон проектирования фабрики

Используйте шаблон Абстрактная фабрика, когда

  • Система должна быть независимой от того, как ее продукты создаются, составляются и представляются.
  • Система должна быть настроена с одним из нескольких семейств продуктов.
  • Семейство связанных объектов продукта предназначено для совместного использования, и вам необходимо применить это ограничение.
  • Вы хотите предоставить библиотеку классов продуктов, и вы хотите раскрыть только их интерфейсы, а не их реализации.

5. Абстрактный шаблон фабрики в JDK

  • java.util.Calendar#getInstance()
  • java.util.Arrays#asList()
  • java.util.ResourceBundle#getBundle()
  • java.sql.DriverManager#getConnection()
  • java.sql.Connection#createStatement()
  • java.sql.Statement#executeQuery()
  • java.text.NumberFormat#getInstance()
  • javax.xml.transform.TransformerFactory#newInstance()

6. Загрузите исходный код

Это был урок по шаблону абстрактного дизайна фабрики. Вы можете скачать исходный код здесь: AbstractFactoryPattern-Project