Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate Abstract Factory to Russian / Fix #2286 partially #2533

Merged
merged 2 commits into from
Aug 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 237 additions & 0 deletions localization/ru/abstract-factory/README.md
Original file line number Diff line number Diff line change
@@ -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());
}

```

## Диаграмма классов
![Диаграмма классов паттерна проектирования абстрактная фабрика](../../../abstract-factory/etc/abstract-factory.urm.png)

## Применимость
Используйте шаблон проектирования абстрактная фабрика, когда:

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

Примеры сценариев использования:

- Выбор необходимой реализации 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)