Привет, Хабр! Представляю вашему вниманию перевод статьи «Design Patterns: Factory Pattern» автора Shubham Zanwar.
Шаблон проектирование Фабрика используется как создающий шаблон, когда пользователь может выбирать между несколькими опциями. Приведу пример.
Давайте представим как бы это работало в магазине домашних животных. Чтобы понимание было полным, нам надо посмотреть на реализацию с двух точек зрения: владельца магазина (разработчик, создающий фабрику) и покупателя (пользователя, использующего интерфейс).
Предположим, что вы владелец магазина с собаками (для упрощения: раздаете щенков). С тех пор как вы в мире IT, каждая собака это экземпляр класса Dog. Когда приходит посетитель, вы просто создаете новый экземпляр Dog и отдаете щенка.
Однако позже посетители просят в подарок еще и котят.
Так как вы умный владелец, вы понимаете, что запросы могут быть и шире. Люди всегда хотят большего.
Вам нужна крепкая масштабируемая система, чтобы генерировать новых питомцев для посетителей. Итак, шаблон Фабрика.
Вы создаете список всех основных особенностей ваших питомцев. Например, они позволяют получить имя животного, звук, который они издают, и возраст. Этот список позволит вам создать интерфейс со следующими функциями:
Теперь вы можете создавать любое количество различных питомцев с этими характеристиками (реализующих этот интерфейс). У вас могут быть кошки, собаки, рыбы, попугаи — все, что реализует интерфейс Pet! Давайте создадим щенка — Dog и котенка — Cat:
Еще одна вещь, которая вам может понадобиться в Фабрике, это возвращать разных питомцев (щенка или котенка) в зависимости от запроса пользователя. Простыми словами, если посетитель просит собаку — даем ему красивого щенка
Обратите внимание, что функция GetPet возвращает Pet — не Dog и не Cat. Эту функцию можно легко расширить, добавив структуры, реализующие Pet интерфейс. Добавление других видов питомцев никак не повлияет на посетителей, желающих только щенка.
Поздравляем! Вы создали магазин домашних животных, используя шаблон проектирования Фабрика️.
Давайте посмотрим с точки зрения пользователя. Всем нужно вызывать функцию GetPet с каким-то конфигом (в данном случае тип питомца). В итоге, они все знаю, что получают тип Pet. Это звучит странно в реальном мире вещей, но возвращаясь к коду: так легче поддерживать абстракцию.
Посетители могут свободно «использовать» Pet, как им нравится. Использование останется таким же независимым от типа питомца, которого они получили (потому что все питомцы реализуют общий интерфейс!!!
Давайте это проверим:
На выходе должны увидеть следующее:
Вы можете найти код для этой статьи на github.
Надеюсь, что теперь вы лучше понимаете шаблон проектирования Фабрика.
Шаблон проектирование Фабрика используется как создающий шаблон, когда пользователь может выбирать между несколькими опциями. Приведу пример.
Магазин домашних животных
Давайте представим как бы это работало в магазине домашних животных. Чтобы понимание было полным, нам надо посмотреть на реализацию с двух точек зрения: владельца магазина (разработчик, создающий фабрику) и покупателя (пользователя, использующего интерфейс).
Взгляд владельца
Предположим, что вы владелец магазина с собаками (для упрощения: раздаете щенков). С тех пор как вы в мире IT, каждая собака это экземпляр класса Dog. Когда приходит посетитель, вы просто создаете новый экземпляр Dog и отдаете щенка.
Однако позже посетители просят в подарок еще и котят.
Так как вы умный владелец, вы понимаете, что запросы могут быть и шире. Люди всегда хотят большего.
Вам нужна крепкая масштабируемая система, чтобы генерировать новых питомцев для посетителей. Итак, шаблон Фабрика.
Вы создаете список всех основных особенностей ваших питомцев. Например, они позволяют получить имя животного, звук, который они издают, и возраст. Этот список позволит вам создать интерфейс со следующими функциями:
type Pet interface {
GetName() string
GetAge() int
GetSound() string
}
Теперь вы можете создавать любое количество различных питомцев с этими характеристиками (реализующих этот интерфейс). У вас могут быть кошки, собаки, рыбы, попугаи — все, что реализует интерфейс Pet! Давайте создадим щенка — Dog и котенка — Cat:
// pet - это структура, реализующая Pet интерфейс
// и может быть использована для создания любого животного
// Смотрите `Dog` и `Cat` ниже
type pet struct {
name string
age int
sound string
}
func (p *pet) GetName() string {
return p.name
}
func (p *pet) GetSound() string {
return p.sound
}
func (p *pet) GetAge() int {
return p.age
}
type Dog struct {
pet
}
type Cat struct {
pet
}
Еще одна вещь, которая вам может понадобиться в Фабрике, это возвращать разных питомцев (щенка или котенка) в зависимости от запроса пользователя. Простыми словами, если посетитель просит собаку — даем ему красивого щенка
func GetPet(petType string) Pet {
if petType == "dog" {
return &Dog{
pet{
name: "Chester",
age: 2,
sound: "bark",
},
}
}
if petType === "cat" {
return &Cat{
pet{
name: "Mr. Buttons",
age: 3,
sound: "meow",
},
}
}
}
Обратите внимание, что функция GetPet возвращает Pet — не Dog и не Cat. Эту функцию можно легко расширить, добавив структуры, реализующие Pet интерфейс. Добавление других видов питомцев никак не повлияет на посетителей, желающих только щенка.
Поздравляем! Вы создали магазин домашних животных, используя шаблон проектирования Фабрика️.
Взгляд посетителя
Давайте посмотрим с точки зрения пользователя. Всем нужно вызывать функцию GetPet с каким-то конфигом (в данном случае тип питомца). В итоге, они все знаю, что получают тип Pet. Это звучит странно в реальном мире вещей, но возвращаясь к коду: так легче поддерживать абстракцию.
Посетители могут свободно «использовать» Pet, как им нравится. Использование останется таким же независимым от типа питомца, которого они получили (потому что все питомцы реализуют общий интерфейс!!!
Давайте это проверим:
func describePet(pet Pet) string {
return fmt.Sprintf("%s is %d years old. It's sound is %s", pet.GetName(), pet.GetAge(), pet.GetSound())
}
func main() {
petType := "dog"
dog := GetPet(petType)
petDescription := describePet(dog)
fmt.Println(petDescription)
fmt.Println("-------------")
petType = "cat"
cat := GetPet(petType)
petDescription = describePet(cat)
fmt.Println(petDescription)
}
На выходе должны увидеть следующее:
Chester is 2 years old. It's sound is bark
-------------
Mr. Buttons is 3 years old. It's sound is meow
Вы можете найти код для этой статьи на github.
Надеюсь, что теперь вы лучше понимаете шаблон проектирования Фабрика.