1. Что такое паттерн Компоновщик
Паттерн Компоновщик - это широко используемый структурный паттерн проектирования объектов. Он объединяет объекты в древовидную структуру для представления иерархических отношений "часть-целое", позволяя клиентам обрабатывать отдельные объекты и объекты-композиции в единообразной манере.
2. Характеристики и преимущества паттерна Компоновщик
Основные преимущества паттерна компоновщик:
- Он позволяет четко определить иерархию сложных объектов, представляя всю или часть иерархии объектов и упрощая добавление новых компонентов.
- Он предоставляет унифицированный интерфейс, обеспечивая однородный доступ к составным частям и отдельным объектам, позволяя клиентам использовать одиночные и составные объекты единообразно.
3. Сценарии применения паттерна Компоновщик
- Когда необходимо представить иерархию части-целого объектов.
- Когда необходимо, чтобы клиенты игнорировали различия между составными объектами и отдельными объектами и единообразно использовали все объекты в составной структуре.
4. Реализация паттерна компоновщик в Golang
Предположим, что мы разрабатываем приложение электронной коммерции, каталог продуктов - отличный пример паттерна компоновщик. Категория может содержать другие категории, а также продукты (например, категория электроники содержит телефоны, компьютеры, и в телефонах есть iPhone, Samsung и т. д.).
4.1 UML Диаграмма классов
4.2 Введение в пример
В этом примере у нас есть Component
(очевидно, используя возможности интерфейса объектно-ориентированного программирования) в качестве абстрактного базового класса, и и Composite
и Leaf
оба реализуют этот интерфейс, представляя объекты-контейнеры и базовые объекты соответственно.
4.3 Шаг реализации 1: Определение абстрактного класса компонента
Этот метод обычно определяется в интерфейсном классе и является ключевой центральной операцией.
4.3.1 Определение интерфейса абстрактного класса компонента
// Component: Базовый интерфейс компонента, определяет общность групп и индивидуальных объектов
type Component interface {
Search(string)
}
4.3.2 Реализация основных методов абстрактного класса компонента
Этот шаг специально реализуется в классе-компоненте контейнера и классе-листе.
4.4 Шаг реализации 2: Определение класса-листа
Этот конкретный класс представляет нижнюю категорию или объект в иерархии и не имеет следующего уровня объектов.
4.4.1 Наследование от абстрактного класса компонента
В Go наследование интерфейсов реализуется посредством методов, реализованных через структуры.
4.4.2 Реализация методов, специфичных для класса-листа
// Product: Представляет листовой узел, то есть продукт, и не может иметь дочерних узлов
type Product struct {
Name string
}
// Search: Поиск продуктов
func (p *Product) Search(keyword string) {
if strings.Contains(p.Name, keyword) {
fmt.Printf("Продукт: '%s' содержит ключевое слово: '%s'\n", p.Name, keyword)
}
}
4.5 Шаг реализации 3: Определение класса-контейнера
Этот класс используется для хранения и управления дочерними объектами, как правило, включая некоторые методы для управления и организации дочерних объектов, такие как add(Component)
, remove(Component)
и т. д.
4.5.1 Наследование от абстрактного класса компонента
Это также реализуется путем использования структур для реализации методов интерфейса в Go.
4.5.2 Реализация методов, специфичных для класса-контейнера
// Category: Представляет контейнерный узел, то есть категорию продуктов, которая может иметь дочерние узлы
type Category struct {
Name string
Children []Component
}
// Add: Добавить дочерний узел
func (c *Category) Add(child Component) {
c.Children = append(c.Children, child)
}
// Remove: Удалить дочерний узел
func (c *Category) Remove(child Component) {
// Особая реализация опущена
}
// Search: Поиск продуктов
func (c *Category) Search(keyword string) {
fmt.Printf("Категория: %s\n", c.Name)
for _, composite := range c.Children {
composite.Search(keyword)
}
}
4.6 Шаг 4 Реализации: Пример клиентского кода
Создайте структуру, соберите ее в древовидную структуру, а затем вызовите операцию доступа к древовидной структуре.
func main() {
root := &Category{Name: "Корень"}
electronics := &Category{Name: "Электроника"}
phone := &Product{Name: "Телефон"}
tv := &Product{Name: "Телевизор"}
root.Add(electronics)
electronics.Add(phone)
electronics.Add(tv)
root.Search("телефон") // Это выполнит поиск во всех дочерних элементах
}