Дисциплины - Объектно-ориентированное программирование

Шаблоны проектирования практических задач - Структурные шаблоны проектирования - Компоновщик

Шаблон «Компоновщик» предполагает, что при разработке «контейнерных» объектов, которые собирают и упорядочивают «объекты содержимого», вы упрощаете операции, если предоставляете контейнерам и объектам содержимого общий набор методов. И тем самым поддерживаете максимум возможных методов при том, что вызывающему неважно, переданы отдельный объект контента или целый контейнер.

Реализация на Phyton

Шаблон «Компоновщик» предполагает, что при разработке «контейнерных» объектов, которые собирают и упорядочивают «объекты содержимого», вы упрощаете операции, если предоставляете контейнерам и объектам содержимого общий набор методов. И тем самым поддерживаете максимум возможных методов при том, что вызывающему неважно, переданы отдельный объект контента или целый контейнер.

Преимущества симметрии, которую создаёт этот паттерн между контейнерами и их содержимым, увеличиваются, только если симметрия делает объекты взаимозаменяемыми. Но здесь некоторые статически типизированные языки встречают препятствие.

В языках со строгой типизацией объекты двух классов взаимозаменяемые только при наследовании от одного родительского класса, который реализует общие методы, или при наследовании одного класса непосредственно от другого.

В других статических языках ограничение мягче. Нет строгой необходимости в том, чтобы контейнер и его содержимое делились реализацией. Пока оба соответствуют «интерфейсу», который объявляет конкретные общие методы, объекты вызываются симметрично.

Так как это программирование на Python, оба ограничения испаряются! Пишите код в предпочтительном для себя диапазоне безопасности и краткости. Хотите, пойдите классическим путём и добавьте общий суперкласс:

class Widget(object):
    def children(self):
        return []

class Frame(Widget):
    def __init__(self, child_widgets):
        self.child_widgets = child_widgets

    def children(self):
        return self.child_widgets

class Label(Widget):
    def __init__(self, text):
        self.text = text

Или задайте объектам один и тот же интерфейс. И положитесь на тесты, которые помогут поддерживать симметрию между контейнерами и содержимым. (Где для простейших скриптов ваш «тест» может быть фактом выполнения кода.)

class Frame(object):
    def __init__(self, child_widgets):
        self.child_widgets = child_widgets

    def children(self):
        return self.child_widgets

class Label(object):
    def __init__(self, text):
        self.text = text

    def children(self):
        return []

Или выберите другой подход из спектра дизайна между этими двумя крайностями. Вот что поддерживает Python:

  • Следуйте классической архитектуре с общим суперклассом, показанной в первом примере выше.
  • Сделайте суперкласс абстрактным базовым классом с помощью инструментов модуля стандартной библиотеки abc.
  • Объявите для двух классов совместно используемый интерфейс, наподобие поддерживаемых старым пакетом zope.interface.
  • Применяйте аннотации для получения жёстких гарантий того, что и контейнер, и содержимое реализуют требуемое поведение. Для этого понадобится установка Python библиотеки проверки типов, к примеру, MyPy.
  • Вы в праве использовать утиную типизацию и не просить ни разрешения, ни прощения!

Поскольку Python предлагает такой спектр подходов, не стоит определять паттерн «Компоновщик» классически, то есть как один конкретный механизм (суперкласс) для создания или гарантирования симметрии. Вместо этого определите его как создание симметрии любыми средствами в иерархии объектов.

Реализация на PHP

abstract class Component
{
	protected $name;

	public function __construct($name)
	{
		$this->name = $name;
	}

	public abstract function display();
}

class Composite extends Component
{
	private $children = array();

	public function add(Component $component)
	{
		$this->children[$component->name] = $component;
	}

	public function remove(Component $component)
	{
		unset($this->children[$component->name]);
	}

	public function display()
	{
		foreach($this->children as $child) {
            $child->display();
        }
	}
}

class Leaf extends Component
{
	public function display()
	{
		print_r($this->name);
	}
}

// Create a tree structure
$root = new Composite("root");

$root->add(new Leaf("Leaf A"));
$root->add(new Leaf("Leaf B"));

$comp = new Composite("Composite X");

$comp->add(new Leaf("Leaf XA"));
$comp->add(new Leaf("Leaf XB"));
$root->add($comp);
$root->add(new Leaf("Leaf C"));

// Add and remove a leaf
$leaf = new Leaf("Leaf D");
$root->add($leaf);
$root->remove($leaf);

// Recursively display tree
$root->display();

Еще один пример с использованием типажей:

interface IComponent {
  function display();
}

trait TComponent
{
    public $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function display()
    {
        print $this->name.'
'.PHP_EOL;
    }
}

trait TComposite
{ 
    use TComponent{
        TComponent::display as displaySelf;
    }

    protected $children = array();

    public function add(IComponent $item)
    {
        $this->children[$item->name] = $item;
    }

    public function remove(IComponent $item)
    {
        unset($this->children[$item->name]);
    }

    public function display()
    {
        $this->displaySelf();
        foreach ($this->children as $child) {
            $child->display();
        }
    }
}

class Composite implements IComponent
{
    use TComposite;
}

class Leaf implements IComponent
{
    use TComponent;
}

$root = new Composite("root");

$root->add(new Leaf("Leaf A"));
$root->add(new Leaf("Leaf B"));

$comp = new Composite("Composite X");

$comp->add(new Leaf("Leaf XA"));
$comp->add(new Leaf("Leaf XB"));
$root->add($comp);
$root->add(new Leaf("Leaf C"));

$leaf = new Leaf("Leaf D");
$root->add($leaf);
$root->remove($leaf);

$root->display();

Количество комментариев: 0

Для того, чтобы оставить коментарий необходимо зарегистрироваться
814301 БГУИР
814302 БГУИР
814303 БГУИР
894351 БГУИР
90421 БГУИР


Изображения Видео

1. Абстрактная фабрика https://www.youtube.com/watch?v=1mVONOCxfLg
2. Фабричный метод https://www.youtube.com/watch?v=5UqUDR6_2cY
3. Шаблон декоратор https://www.youtube.com/watch?v=Lwb9bm8yKD0
4. Dessign patterns on PHP https://github.com/domnikl/DesignPatternsPHP
5. Приёмы объектно-ориентированного проектирования. Паттерны проектирования Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес; [пер. с англ.: А. Слинкин науч. ред.: Н. Шалаев]. — Санкт-Петербург [и др.] : Питер, 2014. — 366 с. : ил. ; 24 см.
6. Приемы объектно-ориентированного проектирования. Паттерны проектирования Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес; [пер. с англ.: А. Слинкин науч. ред.: Н. Шалаев]. — Санкт-Петербург [и др.] : Питер, 2014. — 366 с. : ил. ; 24 см.
7. Ajax http://erud.by/ajax
8. Ajax http://erud.by/ajax
9. Ajax http://erud.by/ajax
10. Документация Laravel http://laravel.com
Задание к курсовой работе
Задание к курсовой работе
Вопросы к экзамену