-
-
Notifications
You must be signed in to change notification settings - Fork 26.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
translation: Translate Abstract Factory to Russian / Fix #2286 partia…
…lly (#2533) * Translate Abstract Factory to Russian * Fix a typo
- Loading branch information
1 parent
5f0da67
commit 376cd21
Showing
1 changed file
with
237 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |