Jump to content

Составной узор

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

Композитный [2] шаблон проектирования — один из двадцати трех известных Шаблоны проектирования GoF которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторно использовать.

Какие проблемы может решить шаблон проектирования «Композитный»?

[ редактировать ]
  • Иерархия часть-целое должна быть представлена ​​так, чтобы клиенты могли единообразно обрабатывать части и целые объекты.
  • Иерархию части-целого следует представлять в виде древовидной структуры.

При определении (1) Part объекты и (2) Whole объекты, которые действуют как контейнеры для Part объекты, клиенты должны обрабатывать их отдельно, что усложняет клиентский код. [3]

Какое решение описывает шаблон проектирования «Композитный»?

[ редактировать ]
  • Определить единую Component интерфейс для обеих частей ( Leaf) предметы и целые ( Composite) объекты.
  • Индивидуальный Leaf объекты реализуют Component интерфейс напрямую и Composite объекты пересылают запросы своим дочерним компонентам.

Это позволяет клиентам работать через Component интерфейс для лечения Leaf и Composite объекты равномерно: Leaf объекты выполняют запрос напрямую, и Composite объекты пересылать запрос своим дочерним компонентам рекурсивно вниз по древовидной структуре. Это упрощает реализацию, изменение, тестирование и повторное использование клиентских классов.

См. также диаграмму классов и объектов UML ниже.

Мотивация

[ редактировать ]

Имея дело с данными с древовидной структурой, программистам часто приходится различать листовой узел и ветвь. Это делает код более сложным и, следовательно, более подверженным ошибкам. Решением является интерфейс, позволяющий единообразно обрабатывать сложные и примитивные объекты. В объектно-ориентированном программировании составной объект — это объект, спроектированный как композиция одного или нескольких аналогичных объектов, обладающих схожей функциональностью. Это известно как отношение « имеет » между объектами. [4] Ключевая концепция заключается в том, что вы можете манипулировать одним экземпляром объекта так же, как если бы вы манипулировали их группой. Операции, которые вы можете выполнять со всеми составными объектами, часто имеют отношение наименьшего общего знаменателя . Например, при определении системы для отображения сгруппированных фигур на экране было бы полезно определить изменение размера группы фигур, чтобы оно имело тот же эффект (в некотором смысле), что и изменение размера одной фигуры.

Когда использовать

[ редактировать ]

Композитный вариант следует использовать, когда клиенты игнорируют разницу между составами объектов и отдельными объектами. [1] Если программисты обнаруживают, что они используют несколько объектов одинаковым образом и часто имеют почти идентичный код для обработки каждого из них, тогда составной объект — хороший выбор; в этой ситуации проще рассматривать примитивы и составные элементы как однородные.

Структура

[ редактировать ]

Диаграмма классов и объектов UML

[ редактировать ]
Пример класса UML и объектной диаграммы для шаблона проектирования «Композит». [5]

На приведенной выше UML классов диаграмме Client класс не относится к Leaf и Composite занятия напрямую (отдельно). Вместо этого Client относится к общему Component интерфейс и может лечить Leaf и Composite равномерно.
Leaf класс не имеет дочерних элементов и реализует Component интерфейс напрямую.
Composite класс поддерживает контейнер дочернего элемента Component объекты ( children) и пересылает запросы этим children ( for each child in children: child.operation()).

Диаграмма взаимодействия объектов показывает взаимодействие во время выполнения: В этом примере Client объект отправляет запрос на верхний уровень Composite объект (типа Component) в древовидной структуре. Запрос пересылается (выполняется) всем дочерним Component объекты ( Leaf и Composite объекты) вниз по древовидной структуре.

Определение дочерних операций
Определение дочерних операций в шаблоне проектирования «Композит». [6]

Существует два варианта дизайна для определения и реализации операций, связанных с дочерними элементами. например добавление/удаление дочернего компонента в/из контейнера ( add(child)/remove(child)) и доступ к дочернему компоненту ( getChild()):

  • Обеспечьте единообразие: дочерние операции определены в Component интерфейс. Это позволяет клиентам лечить Leaf и Composite объекты равномерно. Но безопасность типов теряется, поскольку клиенты могут выполнять операции, связанные с дочерними элементами, над Leaf объекты.
  • Проектирование с учетом типовой безопасности: Дочерние операции определяются только в Composite сорт. Клиенты должны относиться Leaf и Composite объекты по-разному. Но безопасность типов обеспечивается, поскольку клиенты не могут выполнять операции, связанные с дочерними элементами, над Leaf объекты.

В шаблоне проектирования Composite основное внимание уделяется единообразию , а не безопасности типов .

Диаграмма классов UML

[ редактировать ]
Составной шаблон в UML .
Компонент
  • — абстракция для всех компонентов, включая составные
  • объявляет интерфейс для объектов в композиции
  • (необязательно) определяет интерфейс для доступа к родительскому элементу компонента в рекурсивной структуре и реализует его, если это необходимо.
Лист
  • представляет листовые объекты в композиции
  • реализует все методы компонента
Композитный
  • представляет составной компонент (компонент, имеющий дочерние элементы)
  • реализует методы манипулирования детьми
  • реализует все методы компонента, обычно делегируя их своим дочерним элементам.
Составной узор в LePUS3 .

Вариация

[ редактировать ]

Как описано в разделе «Шаблоны проектирования» , этот шаблон также предполагает включение методов манипулирования дочерними элементами в основной интерфейс компонента, а не только в подкласс Composite. В более поздних описаниях эти методы иногда опускаются. [7]

Эта реализация C++14 основана на реализации до C++98, описанной в книге.

#include <iostream>
#include <string>
#include <list>
#include <memory>
#include <stdexcept>

typedef double Currency;

// declares the interface for objects in the composition.
class Equipment { // Component
public:
  // implements default behavior for the interface common to all classes, as appropriate.
  virtual const std::string& getName() {
    return name;
  }
  virtual void setName(const std::string& name_) {
    name = name_;
  }
  virtual Currency getNetPrice() {
    return netPrice;
  }
  virtual void setNetPrice(Currency netPrice_) {
    netPrice = netPrice_;
  }
  // declares an interface for accessing and managing its child components.
  virtual void add(std::shared_ptr<Equipment>) = 0;
  virtual void remove(std::shared_ptr<Equipment>) = 0;
  virtual ~Equipment() = default;
protected:
  Equipment() :name(""), netPrice(0) {}
  Equipment(const std::string& name_) :name(name_), netPrice(0) {}
private:
  std::string name;
  Currency netPrice;
};

// defines behavior for components having children.
class CompositeEquipment : public Equipment { // Composite
public:
  // implements child-related operations in the Component interface.
  virtual Currency getNetPrice() override {
    Currency total = Equipment::getNetPrice();
    for (const auto& i:equipment) {
      total += i->getNetPrice();
    }
    return total;
  }
  virtual void add(std::shared_ptr<Equipment> equipment_) override {
    equipment.push_front(equipment_.get());
  }
  virtual void remove(std::shared_ptr<Equipment> equipment_) override {
    equipment.remove(equipment_.get());
  }
protected:
  CompositeEquipment() :equipment() {}
  CompositeEquipment(const std::string& name_) :equipment() {
    setName(name_);
  }
private:
  // stores child components.
  std::list<Equipment*> equipment;
};

// represents leaf objects in the composition.
class FloppyDisk : public Equipment { // Leaf
public:
  FloppyDisk(const std::string& name_) {
    setName(name_);
  }
  // A leaf has no children.
  void add(std::shared_ptr<Equipment>) override {
    throw std::runtime_error("FloppyDisk::add");
  }
  void remove(std::shared_ptr<Equipment>) override {
    throw std::runtime_error("FloppyDisk::remove");
  }
};

class Chassis : public CompositeEquipment {
public:
  Chassis(const std::string& name_) {
    setName(name_);
  }
};

int main() {
  // The smart pointers prevent memory leaks.
  std::shared_ptr<FloppyDisk> fd1 = std::make_shared<FloppyDisk>("3.5in Floppy");
  fd1->setNetPrice(19.99);
  std::cout << fd1->getName() << ": netPrice=" << fd1->getNetPrice() << '\n';

  std::shared_ptr<FloppyDisk> fd2 = std::make_shared<FloppyDisk>("5.25in Floppy");
  fd2->setNetPrice(29.99);
  std::cout << fd2->getName() << ": netPrice=" << fd2->getNetPrice() << '\n';

  std::unique_ptr<Chassis> ch = std::make_unique<Chassis>("PC Chassis");
  ch->setNetPrice(39.99);
  ch->add(fd1);
  ch->add(fd2);
  std::cout << ch->getName() << ": netPrice=" << ch->getNetPrice() << '\n';

  fd2->add(fd1);
}

Вывод программы

3.5in Floppy: netPrice=19.99
5.25in Floppy: netPrice=29.99
PC Chassis: netPrice=89.97
terminate called after throwing an instance of 'std::runtime_error'
  what():  FloppyDisk::add

См. также

[ редактировать ]
  1. ^ Jump up to: а б Гамма, Эрих; Ричард Хелм; Ральф Джонсон; Джон М. Влиссидес (1995). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Аддисон-Уэсли. стр. 395 . ISBN  0-201-63361-2 .
  2. ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли. стр. 163 и далее . ISBN  0-201-63361-2 . {{cite book}}: CS1 maint: несколько имен: список авторов ( ссылка )
  3. ^ «Шаблон композитного проектирования — проблема, решение и применимость» . w3sDesign.com . Проверено 12 августа 2017 г.
  4. ^ Скотт Уолтерс (2004). Книга шаблонов проектирования Perl . Архивировано из оригинала 8 марта 2016 г. Проверено 18 января 2010 г.
  5. ^ «Шаблон проектирования «Композитный — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.
  6. ^ «Шаблон проектирования «Композитный. Реализация» . w3sDesign.com . Проверено 12 августа 2017 г.
  7. ^ Гири, Дэвид (13 сентября 2002 г.). «Взгляд на шаблон проектирования Composite» . Шаблоны проектирования Java. JavaWorld . Проверено 20 июля 2020 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: ee817a6e221ccf64827421a54a46b1fd__1716814500
URL1:https://arc.ask3.ru/arc/aa/ee/fd/ee817a6e221ccf64827421a54a46b1fd.html
Заголовок, (Title) документа по адресу, URL1:
Composite pattern - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)