В этой статье мы увидим, что такое Составной шаблон. Давай займемся этим!

Введение

Составной шаблон - это Структурный шаблон, который позволяет нам обрабатывать группу объектов так же, как отдельный экземпляр объекта.

Формальное определение составного шаблона говорит примерно так (Википедия):

«В программной инженерии составной шаблон - это шаблон проектирования секционирования. Составной шаблон описывает, что группа объектов должна обрабатываться так же, как один экземпляр объекта. Назначение составного объекта состоит в том, чтобы «составить» объекты в древовидные структуры для представления иерархий «часть-целое». Реализация составного шаблона позволяет клиентам одинаково обрабатывать отдельные объекты и композиции. "

Это определение может показаться трудным для понимания, когда мы читаем его впервые. Итак, другой способ определения этого шаблона с использованием простых слов может привести нас к выводу, что Составной шаблон позволяет клиентам обрабатывать отдельные объекты единообразно.

Остается немного темно. Примером из реальной жизни может служить компания, состоящая из сотрудников разных категорий, и все они имеют зарплату, некоторые обязанности и могут или не могут подчиняться кому-то или иметь некоторых подчиненных. Мы также можем рассматривать это как программу, которая может печатать некоторую графику, и каждая из них может состоять из одной строки или быть композицией из нескольких графиков. Мы также можем представить его как программу, которая управляет файловой системой, которая представляет собой древовидную структуру, содержащую папки и файлы. Папки могут содержать один или несколько файлов или папок. Файлы и папки имеют много общих операций и атрибутов, поэтому удобнее обращаться с ними обоими одинаково.

Определения

Составной узор состоит из следующих объектов:

Компонент

Компонент - это абстракция для всех Компонентов, включая Составные. Он объявляет интерфейс для объектов в композиции. Это может быть интерфейс или абстрактный класс с некоторыми общими для всех объектов методами. Он также объявляет интерфейс для доступа к дочерним компонентам и управления ими.

Лист

У Leaf нет дочерних элементов. Таким образом, он представляет объекты Leaf в композиции и реализует все методы Component.

Композитный

Он представляет Компоненты, у которых есть дочерние элементы, и реализует методы для управления дочерними элементами и всеми методами Компонент, обычно делегируя их своим дочерним элементам. Он также предоставляет дополнительные методы для добавления, удаления и получения компонентов.

Клиент

Клиент управляет объектами в иерархии через интерфейс Компонент.

Шаблон

Целью этого шаблона является объединение объектов в древовидные структуры для представления иерархий «часть-целое». Этот шаблон также полезен, когда мы хотим, чтобы клиент мог игнорировать разницу между составами объектов и отдельными объектами.

Составной шаблон создает класс, содержащий группу собственных объектов, и этот класс предоставляет способы изменения своей группы одинаковых объектов.

В этом шаблоне Клиент использует интерфейс класса Component для взаимодействия с объектами в структуре композиции. Если объект является Leaf, тогда запрос обрабатывается напрямую, а если это Composite, то запрос перенаправляется дочерним Components .

Интересно отметить, что Composite и Decorator имеют похожие структурные схемы. Тем не менее, Decorator позволяет нам добавлять обязанности к объектам без создания подклассов, в то время как Composite фокусируется на представлении. Между прочим, Composite может использовать Decorator для переопределения свойств композиции, через которую можно пройти с помощью Iterator.

Примеры

Мы собираемся сделать пару примеров, чтобы проиллюстрировать этот паттерн.

Система форм

Допустим, мы хотим создать систему, которая позволяет нам создавать веб-форму, добавлять в нее множество входных данных, а затем отображать ее. Мы собираемся использовать PHP в качестве примера.

Сначала мы создаем интерфейс для рендеринга, Компонент:

interface RenderableInterface
{
    public function render(): string;
}

Теперь давайте создадим несколько элементов для нашей формы, Leafs:

class InputElement implements RenderableInterface
{
    public function render(): string
    {
        return '<input type="text" />';
    }
    
}
class TextElement implements RenderableInterface
{
    private $text;
    
    public function __construct(string $text)
    {
        $this->text = $text;
    }
    
    public function render(): string
    {
        return $this->text;
    }
    
}

Теперь мы можем создать саму форму, Composite:

class Form implements RenderableInterface
{
    private $elements;
    public function render(): string
    {
        $form = '<form>';
        foreach ($this->elements as $element) {
            $form .= $element->render();
        }
        $form .= '</form>';
        return $form;
    }
    public function addElement(RenderableInterface $element)
    {
        $this->elements[] = $element;
    }
    
}

Мы можем использовать нашу систему так:

$form = Form();
$form->addElement(TextElement('First Name:'));
$form->addElement(InputElement());
$form->addElement(TextElement('Last Name:'));
$form->addElement(InputElement());
$form->render();

Программа для рисования

Попробуем сделать простую реализацию нашей программы для рисования. Здесь мы собираемся использовать Java.

Сначала мы создаем интерфейс для фигур, Компонент:

public interface Shape {
    public void draw();
}

Теперь давайте создадим элемент Leaf:

public class Line implements Shape {
    public Line(int x1, int y1, int x2, int y2) {
        // Do something or not
    }
    public void draw() {
        System.out.println("Line at " + x1 + " " + y1 + " " + x2 + " " + y2);
    }
}

А теперь мы создаем сложную форму, Composite:

public class Rectangle implements Shape {
    Shape[] edges = {new Line(-1,-1,1,-1), new Line(-1,1,1,1), new Line(-1,-1,-1,1), new Line(1,-1,1,1)};
    
    public void draw() {
        for (Shape s : edges) {
            s.draw();
            
        }
        
    }
}

Клиент может быть примерно таким:

public class editor {
    public static void main(String[] args) {
    
        List shapes = new ArrayList();
    
        Shape line = new Line(0,0,1,1);
        Shape rectangle = new Rectangle();
        
        shapes.add(line);
        shapes.add(rectangle);
        
        render(shapes);
    
    }
    
    private static void render(List shapes) {
    
        for (Shape s : shapes){
            s.draw();
        }
    
    }
}

Вывод

В этом посте мы узнали, что такое Составной шаблон и как он работает. Мы видели, что он основан на четырех элементах: Component, Leaf, Composite и Client. Этот шаблон позволяет клиентам одинаково обращаться с отдельными объектами.

Последнее слово

Если вам понравилась эта статья, вы можете поддержать и помочь мне на Patreon! Это было бы круто! В противном случае вы можете найти другие мои сообщения на Medium и Tumblr. Вы также узнаете обо мне больше на моем личном сайте. До следующего раза, счастливая головная боль!