mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-14 08:58:26 +00:00
* Translate Abstract Factory to Russian * Fix a typo
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
---
|
||||
title: Abstract Factory
|
||||
category: Creational
|
||||
language: ru
|
||||
tag:
|
||||
- Gang of Four
|
||||
---
|
||||
|
||||
## Альтернативные названия
|
||||
Kit
|
||||
|
||||
## Цель
|
||||
Предоставление интерфейса для создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов.
|
||||
|
||||
## Объяснение
|
||||
Пример из реального мира:
|
||||
> Представьте, что вы хотите создать королевство с замком, королём и армией. Эльфийскому королевству понадобится эльфийский замок, эльфийский король и эльфийская армия, в то время как оркскому королевству понадобится оркский замок, оркский король и оркская армия. Между объектами королевства существует взаимозависимость.
|
||||
|
||||
Простыми словами:
|
||||
> Фабрика фабрик; фабрика, которая объединяет отдельные, но взаимозависимые/взаимозаменяемые фабрики без указания их конкретных классов.
|
||||
|
||||
Википедия пишет:
|
||||
> Порождающий шаблон проектирования, предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов.
|
||||
|
||||
**Программный пример**\
|
||||
Основываясь на примере королевства выше, во-первых, нам понадобятся интерфейсы и реализации для объектов в королевстве.
|
||||
|
||||
```java
|
||||
public interface Castle {
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
public interface King {
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
public interface Army {
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
// Эльфийская реализация
|
||||
public class ElfCastle implements Castle {
|
||||
static final String DESCRIPTION = "Это эльфийский замок!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
public class ElfKing implements King {
|
||||
static final String DESCRIPTION = "Это эльфийский король!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
public class ElfArmy implements Army {
|
||||
static final String DESCRIPTION = "Это эльфийская армия!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
|
||||
// Оркская реализация
|
||||
public class OrcCastle implements Castle {
|
||||
static final String DESCRIPTION = "Это оркский замок!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
public class OrcKing implements King {
|
||||
static final String DESCRIPTION = "Это оркский король!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
public class OrcArmy implements Army {
|
||||
static final String DESCRIPTION = "Это оркская армия!";
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Во-вторых, нам понадобятся абстракция фабрики королевства, а также реализации этой абстракции:
|
||||
|
||||
```java
|
||||
public interface KingdomFactory {
|
||||
Castle createCastle();
|
||||
King createKing();
|
||||
Army createArmy();
|
||||
}
|
||||
|
||||
public class ElfKingdomFactory implements KingdomFactory {
|
||||
|
||||
@Override
|
||||
public Castle createCastle() {
|
||||
return new ElfCastle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public King createKing() {
|
||||
return new ElfKing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Army createArmy() {
|
||||
return new ElfArmy();
|
||||
}
|
||||
}
|
||||
|
||||
public class OrcKingdomFactory implements KingdomFactory {
|
||||
|
||||
@Override
|
||||
public Castle createCastle() {
|
||||
return new OrcCastle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public King createKing() {
|
||||
return new OrcKing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Army createArmy() {
|
||||
return new OrcArmy();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
На данный момент, у нас есть абстрактная фабрика, которая позволяет создавать семейство взаимосвязанных объектов, то есть фабрика эльфийского королевства создаёт эльфийский замок, эльфийского короля, эльфийскую армию и так далее:
|
||||
|
||||
```java
|
||||
var factory = new ElfKingdomFactory();
|
||||
var castle = factory.createCastle();
|
||||
var king = factory.createKing();
|
||||
var army = factory.createArmy();
|
||||
|
||||
castle.getDescription();
|
||||
king.getDescription();
|
||||
army.getDescription();
|
||||
```
|
||||
|
||||
Вывод программы:
|
||||
|
||||
```
|
||||
Это эльфийский замок!
|
||||
Это эльфийский король!
|
||||
Это эльфийская армия!
|
||||
```
|
||||
|
||||
Можно спроектировать фабрику для наших различных фабрик королевств. В следующем примере, мы создали `FactoryMaker`, который ответственен за создание экземпляра `ElfKingdomFactory`, либо `OrcKingdomFactory`.
|
||||
|
||||
Клиент может использовать класс `FactoryMaker`, чтобы создать желаемую конкретную фабрику, которая в свою очередь будет производить разные конкретные объекты, унаследованные от `Castle`, `King`, `Army`.
|
||||
|
||||
В этом примере использовано перечисление, чтобы параметризовать то, какую фабрику королевства запрашивает клиент:
|
||||
|
||||
```java
|
||||
public static class FactoryMaker {
|
||||
public enum KingdomType {
|
||||
ELF, ORC
|
||||
}
|
||||
|
||||
public static KingdomFactory makeFactory(KingdomType type) {
|
||||
return switch (type) {
|
||||
case ELF -> new ElfKingdomFactory();
|
||||
case ORC -> new OrcKingdomFactory();
|
||||
default -> throe new IllegalArgumentException("Данный тип королества не поддерживается.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
var app = new App();
|
||||
|
||||
LOGGER.info("Эльфийское королевство");
|
||||
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
|
||||
LOGGER.indo(app.getCastle().getDescription());
|
||||
LOGGER.indo(app.getKinv().getDescription());
|
||||
LOGGER.indo(app.getArmy().getDescription());
|
||||
|
||||
LOGGER.info("Оркское королевство");
|
||||
|
||||
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
|
||||
LOGGER.indo(app.getCastle().getDescription());
|
||||
LOGGER.indo(app.getKinv().getDescription());
|
||||
LOGGER.indo(app.getArmy().getDescription());
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Диаграмма классов
|
||||

|
||||
|
||||
## Применимость
|
||||
Используйте шаблон проектирования абстрактная фабрика, когда:
|
||||
|
||||
- Система должна быть независимой от того, как создаются, составляются и представляются её продукты;
|
||||
- Система должна быть сконфигурирована одним из нескольких семейств продуктов;
|
||||
- Семейство связанных продуктов спроектировано для совместного использования и вам необходимо обеспечить соблюдение данного ограничения;
|
||||
- Вы хотите предоставить библиотеку классов, но готовы раскрыть только их интерфейсы, но не реализацию;
|
||||
- Время жизни зависимости концептуально короче, чем время жизни потребителя;
|
||||
- Вам требуется значение времени исполнения, чтобы создать требуемую зависимость;
|
||||
- Вы хотите решить какие продукты из семейства вам нужны во время исполнения;
|
||||
- Вам нужно предоставить один или несколько параметров, которые известны только во время исполнения прежде, чем вы сможете решить зависимость;
|
||||
- В случае, когда требуется последовательность среди продуктов;
|
||||
- Вы не хотите менять существующий код, когда добавляются новые продукты или семейство продуктов в программе.
|
||||
|
||||
Примеры сценариев использования:
|
||||
|
||||
- Выбор необходимой реализации FileSystemAcmeService или DataBaseAcmeSerivce или NetworkAcmeService во времени выполнения;
|
||||
- Написание модульных тестов становится намного легче;
|
||||
- Элементы графического пользовательского интерфейса для различных операционных систем.
|
||||
|
||||
## Следствия
|
||||
- Внедрение зависимости в Java скрывает зависимости класса, приводящие к ошибкам времени выполнения, которые могли-бы быть обнаружены во времени компиляции;
|
||||
- Данный паттерн проектирования отлично справляется с задачей создания уже определённых объектов, но добавление новых может быть трудоёмким;
|
||||
- Код становится сложнее, чем ему следует из-за появления большого количества новых интерфейсов и классов, которые появляются вместе с этим паттерном проектирования.
|
||||
|
||||
## Руководства
|
||||
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
||||
|
||||
## Известные применения
|
||||
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
||||
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
|
||||
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
|
||||
|
||||
## Родственные паттерны проектирования
|
||||
* [Factory Method](https://java-design-patterns.com/patterns/factory-method/)
|
||||
* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
|
||||
|
||||
## Благодарности
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
||||
Reference in New Issue
Block a user