У вас вопросы?
У нас ответы:) SamZan.net

На тему- Шаблони проектування Паттерн Proxy заместитель surrogte суррогат Паттерн Interpreter интерпетатор Патт

Работа добавлена на сайт samzan.net:

Поможем написать учебную работу

Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.

Предоплата всего

от 25%

Подписываем

договор

Выберите тип работы:

Скидка 25% при заказе до 29.12.2024

МІНІСТЕРСТВО ОСВІТИ НАУКИ ТА СПОРТУ УКРАЇНИ

ЖИТОМИРСЬКИЙ ДЕРЖАВНИЙ ТЕХНОЛОГІЧНИЙ УНІВЕРСИТЕТ

ФІКТ

ПІК-8

Курсовий проект

З дисципліни Архітектура та дизайн ПЗ

На тему: Шаблони проектування

Паттерн Proxy (заместитель, surrogate, суррогат)

Паттерн Interpreter (интерпетатор)

Паттерн Composite (компоновщик)

Виконав:  Євпак В.А.

Перевірив:  Левченко А.Ю.

Житомир 2012р.

UML (англ. Unified Modeling Language — унифицированный язык моделирования) — язык графического описания для объектного моделирования в области разработки программного обеспечения. UML является языком широкого профиля, это — открытый стандарт, использующий графические обозначения для создания абстрактной модели системы, называемой UML-моделью. UML был создан для определения, визуализации, проектирования и документирования, в основном, программных систем. UML не является языком программирования, но на основании UML-моделей возможна генерация кода.

Использование

Использование UML не ограничивается моделированием программного обеспечения. Его также используют для моделирования бизнес-процессовсистемного проектирования и отображения организационных структур.

UML позволяет также разработчикам программного обеспечения достигнуть соглашения в графических обозначениях для представления общих понятий (таких как класс, компонент, обобщение (англ. generalization), агрегация (англ. aggregation) и поведение) и больше сконцентрироваться на проектировании и архитектуре.

История





История объектно-ориентированных методов и нотации.

До UML 1.x

В 1994 году Гради Буч и Джеймс Рамбо, работавшие в компании Rational Software, объединили свои усилия для создания нового языка объектно-ориентированного моделирования. За основу языка ими были взяты методы моделирования, разработанные Бучем и Рамбо (Object-Modeling Technique, OMT). OMT был ориентирован на анализ, а Booch — на проектирование программных систем. В октябре 1995 года была выпущена предварительная версия 0.8 унифицированного метода (англ. Unified Method). Осенью 1995 года к компании Rational присоединился Ивар Якобсон, автор метода Object-Oriented Software Engineering — OOSE. OOSE обеспечивал превосходные возможности для спецификации бизнес-процессов и анализа требований при помощисценариев использования. OOSE был также интегрирован в унифицированный метод.

На этом этапе основная роль в организации процесса разработки UML перешла к консорциуму OMG (Object Management Group). Группа разработчиков в OMG, в которую также входили Буч, Рамбо и Якобсон, выпустила спецификации UML версий 0.9 и 0.91 в июне и октябре 1996 года.

UML 1.x

Версия

Дата принятия

1.1

ноябрь 1997[1]

1.3

март 2000[2]

1.4

сентябрь 2001[3]

1.4.2.

июль 2004[2]

1.5

март 2003[4]

2.0

июль 2005[5]

2.1

формально не была принята[2]

2.1.1

август 2007[6]

2.1.2

ноябрь 2007[7]

2.2

февраль 2009[8]

2.3

май 2010[9]

2.4 beta 2

март 2011[10]

На волне растущего интереса к UML к разработке новых версий языка в рамках консорциума UML Partners присоединились такие компании, как Digital Equipment Corporation, Hewlett-Packard, i-Logix, IntelliCorp, IBM, ICON Computing, MCI Systemhouse,Microsoft, Oracle Corporation, Rational Software, Texas Instruments и Unisys. Результатом совместной работы стала спецификация UML 1.0, вышедшая в январе 1997 года. В ноябре того же года за ней последовала версия 1.1, содержавшая улучшения нотации, а также некоторые расширения семантики.

Последующие релизы UML включали версии 1.3, 1.4 и 1.5, опубликованные, соответственно, в июне 1999, сентябре 2001 и марте 2003 года.

UML 2.x

Формальная спецификация последней версии UML 2.0 опубликована в августе 2005 года. Семантика языка была значительно уточнена и расширена для поддержки методологии Model Driven Development — MDD  (англ.). Последняя версия UML 2.4.1 опубликована в августе 2011 года.

UML 1.4.2 принят в качестве международного стандарта ISO/IEC 19501:2005.

Преимущества UML

  •  UML объектно-ориентирован, в результате чего методы описания результатов анализа и проектирования семантически близки к методам программирования на современных объектно-ориентированных языках;
  •  UML позволяет описать систему практически со всех возможных точек зрения и разные аспекты поведения системы;
  •  Диаграммы UML сравнительно просты для чтения после достаточно быстрого ознакомления с его синтаксисом;
  •  UML расширяет и позволяет вводить собственные текстовые и графические стереотипы, что способствует его применению не только в сфере программной инженерии;
  •  UML получил широкое распространение и динамично развивается.

Диаграммы

В UML используются следующие виды диаграмм (для исключения неоднозначности приведены также обозначения на английском языке):

Структурные диаграммы:

  •  Диаграмма классов
  •  Диаграмма компонентов
  •  Композитной/составной структуры
    •  Диаграмма кооперации (UML2.0)
  •  Диаграмма развёртывания
  •  Диаграмма объектов
  •  Диаграмма пакетов
  •  Диаграмма профилей (UML2.2)

Диаграммы поведения:

  •  Диаграмма деятельности
  •  Диаграмма состояний
  •  Диаграмма прецедентов
  •  Диаграммы взаимодействия:
    •  Диаграмма коммуникации (UML2.0) / Диаграмма кооперации (UML1.x)
    •  Диаграмма обзора взаимодействия (UML2.0)
    •  Диаграмма последовательности
    •  Диаграмма синхронизации (UML2.0)

Структуру диаграмм UML 2.3 можно представить на диаграмме классов UML:

Паттерн Proxy (заместитель, surrogate, суррогат)

Назначение паттерна Proxy

Паттерн Proxy является суррогатом или замеcтителем другого объекта и контролирует доступ к нему.

Предоставляя дополнительный уровень косвенности при доступе к объекту, может применяться для поддержки распределенного, управляемого или интеллектуального доступа.

Являясь "оберткой" реального компонента, защищает его от излишней сложности.

Решаемая проблема

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

Обсуждение паттерна Proxy

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

Существует четыре ситуации, когда можно использовать паттерн Proxy:

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

Удаленный proxy предоставляет локального представителя для объекта, который находится в другом адресном пространстве ("заглушки" в RPC и CORBA).

Защитный proxy контролирует доступ к основному объекту. "Суррогатный" объект предоставляет доступ к реальному объекту, только вызывающий объект имеет соответствующие права.

Интеллектуальный proxy выполняет дополнительные действия при доступе к объекту.

Вот типичные области применения интеллектуальных proxy:

Подсчет числа ссылок на реальный объект. При отсутствии ссылок память под объект автоматически освобождается (известен также как интеллектуальный указатель или smart pointer).

Загрузка объекта в память при первом обращении к нему.

Установка запрета на изменение реального объекта при обращении к нему других объектов.

Структура паттерна Proxy

Заместитель Proxy и реальный объект RealSubject имеют одинаковые интерфейсы класса Subject, поэтому заместитель может использоваться "прозрачно" для клиента вместо реального объекта.

UML-диаграмма классов паттерна Proxy

Пример паттерна Proxy

Паттерн Proxy для доступа к реальному объекту использует его суррогат или заместитель. Банковский чек является заместителем денежных средств на счете. Чек может быть использован вместо наличных денег для совершения покупок и, в конечном счете, контролирует доступ к наличным деньгам на счете чекодателя.

Использование паттерна Proxy

Определите ту часть системы, которая лучше всего реализуется через суррогата.

Определите интерфейс, который сделает суррогата и оригинальный компонент взаимозаменяемыми.

Рассмотрите вопрос об использовании фабрики, инкапсулирующей решение о том, что желательно использовать на практике: оригинальный объект или его суррогат.

Класс суррогата содержит указатель на реальный объект и реализует общий интерфейс.

Указатель на реальный объект может инициализироваться в конструкторе или при первом использовании.

Методы суррогата выполняют дополнительные действия и вызывают методы реального объекта.

Особенности паттерна Proxy

Adapter предоставляет своему объекту другой интерфейс . Proxy предоставляет тот же интерфейс. Decorator предоставляет расширенный интерфейс.

Decorator и Proxy имеют разные цели, но схожие структуры. Оба вводят дополнительный уровень косвенности: их реализации хранят ссылку на объект, на который они отправляют запросы.

Реализация паттерна Proxy

Паттерн Proxy: до и после

До

Proxy in PHP

Read full article

In the proxy pattern one class stands in for and handles all access to another class.

This can be because the real subject is in a different location (server, platform, etc), the real subject is cpu or memory intensive to create and is only created if necessary, or to control access to the real subject. A proxy can also be used to add additional access functionality, such as recording the number of times the real subject is actually called.

In this example, the ProxyBookList is created in place of the more resource intensive BookList. ProxyBookList will only instantiate BookList the first time a method in BookList is called.

<?php

class ProxyBookList {

   private $bookList = NULL;

   //bookList is not instantiated at construct time

   function __construct() {    }

   function getBookCount() {

       if (NULL == $this->bookList) {

           $this->makeBookList();         }

       return $this->bookList->getBookCount();    }

   function addBook($book) {

       if (NULL == $this->bookList) {

           $this->makeBookList();         }

       return $this->bookList->addBook($book);    }  

   function getBook($bookNum) {

       if (NULL == $this->bookList) {

           $this->makeBookList();        }

       return $this->bookList->getBook($bookNum);    }

   function removeBook($book) {

       if (NULL == $this->bookList) {

           $this->makeBookList();        }

       return $this->bookList->removeBook($book);    }

   //Create

   function makeBookList() {

       $this->bookList = new bookList();    }}

class BookList {

   private $books = array();

   private $bookCount = 0;

   public function __construct() {   }

   public function getBookCount() {    return $this->bookCount;    }

   private function setBookCount($newCount) {

       $this->bookCount = $newCount;    }

   public function getBook($bookNumberToGet) {

       if ( (is_numeric($bookNumberToGet)) && ($bookNumberToGet <= $this->getBookCount()))

           return $this->books[$bookNumberToGet];

       } else {

          return NULL;        }    }

   public function addBook(Book $book_in) {

       $this->setBookCount($this->getBookCount() + 1);

       $this->books[$this->getBookCount()] = $book_in;

       return $this->getBookCount();    }

   public function removeBook(Book $book_in) {

       $counter = 0;

       while (++$counter <= $this->getBookCount()) {

         if ($book_in->getAuthorAndTitle() == $this->books[$counter]->getAuthorAndTitle()) {

           for ($x = $counter; $x < $this->getBookCount(); $x++) {

             $this->books[$x] = $this->books[$x + 1];          }

         $this->setBookCount($this->getBookCount() - 1);        }      }

     return $this->getBookCount();    }}

class Book {

   private $author;

   private $title;

   function __construct($title_in, $author_in) {

     $this->author = $author_in;

     $this->title  = $title_in;    }

   function getAuthor() {

       return $this->author;    }

   function getTitle() {

       return $this->title;    }

   function getAuthorAndTitle() {

     return $this->getTitle().' by '.$this->getAuthor();    }}

 writeln( 'BEGIN TESTING PROXY PATTERN';

 writeln('');

 $proxyBookList = new ProxyBookList();

 $inBook = new Book('PHP for Cats','Larry Truett');

 $proxyBookList->addBook($inBook);

 writeln('test 1 - show the book count after a book is added');

 writeln($proxyBookList->getBookCount());

 writeln('');

  writeln('test 2 - show the book');

 $outBook = $proxyBookList->getBook(1);

 writeln($outBook->getAuthorAndTitle());

 writeln('');

  $proxyBookList->removeBook($outBook);

  writeln('test 3 - show the book count after a book is removed');

 writeln($proxyBookList->getBookCount());

 writeln('');

 writeln('END TESTING PROXY PATTERN');

 function writeln($line_in) {

   echo $line_in."<br/>";  }?>

BEGIN TESTING PROXY PATTERN

test 1 - show the book count after a book is added

test 2 - show the book

PHP for Cats by Larry Truett

test 3 - show the book count after a book is removed

END TESTING PROXY PATTERN ttp://sourcemaking.com/design_patterns/proxy/

Краткая историческая справка

Паттерн Interpreter

По паттерну найти исторических сведеней не удалось. Россмотрены такие сайты:

  1.  http://www.codelab.ru/p/interpreter/
    1.  http://ru.wikipedia.org/wiki/Интерпретатор_(шаблон_проектирования)
      1.  http://crazycode.net/blog/6-architecture/12-behavioral-patterns

Паттерн Interpreter (интерпетатор)

Назначение паттерна Interpreter

Для заданного языка определяет представление его грамматики, а также интерпретатор предложений этого языка.

Отображает проблемную область в языке, язык – в грамматику, а грамматику – в иерархии объектно-ориентированного проектирования.

Решаемая проблема

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

Обсуждение паттерна Interpreter

Паттерн Interpreter определяет грамматику простого языка для проблемной области, представляет грамматические правила в виде языковых предложений и интерпретирует их для решения задачи. Для представления каждого грамматического правила паттерн Interpreter использует отдельный класс. А так как грамматика, как правило, имеет иерархическую структуру, то иерархия наследования классов хорошо подходит для ее описания.

Абстрактный базовый класс определяет метод interpret(), принимающий (в качестве аргумента) текущее состояние языкового потока. Каждый конкретный подкласс реализует метод interpret(), добавляя свой вклад в процесс решения проблемы.

Структура паттерна Interpreter

Паттерн Interpreter моделирует проблемную область с помощью рекурсивной грамматики. Каждое грамматическое правило может быть либо составным (правило ссылается на другие правила) либо терминальным (листовой узел в структуре ”дерево”).

Для рекурсивного обхода ”предложений” при их интерпретации используется паттерн Composite.

UML-диаграмма классов паттерна Interpreter

Пример паттерна Interpreter

Паттерн Intepreter определяет грамматическое представление для языка и интерпретатор для интерпретации грамматики. Музыканты являются примерами интерпретаторов. Тональность и продолжительность звуков могут быть описаны нотами. Такое представление является музыкальным языком. Музыканты, используя ноты, способны воспроизвести оригинальные частоту и длительность каждого представленного звука.

Использование паттерна Interpreter

Определите “малый“ язык, “инвестиции” в который будут оправданными.

Разработайте грамматику для языка.

Для каждого грамматического правила (продукции) создайте свой класс.

Полученный набор классов организуйте в структуру с помощью паттерна Composite.

В полученной иерархии классов определите метод interpret(Context).

Объект Context инкапсулирует информацию, глобальную по отношению к интерпретатору. Используется классами во время процесса ”интерпретации”.

Особенности паттерна Interpreter

Абстрактное синтаксическое дерево интерпретатора – пример паттерна Composite.

Для обхода узлов дерева может применяться паттерн Iterator.

Терминальные символы могут разделяться c помощью Flyweight.

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

Реализация паттерна Interpreter

Совместное использование паттернов Interpreter и Template Method

Рассмотрим задачу интерпретирования (вычисления) значений строковых представлений римских чисел. Используем следующую грамматику.

romanNumeral ::= {thousands} {hundreds} {tens} {ones}

thousands,hundreds,tens,ones ::= nine | four | {five} {one} {one} {one}

nine ::= "CM" | "XC" | "IX"

four ::= "CD" | "XL" | "IV"

five ::= 'D' | 'L' | 'V'

one  ::= 'M' | 'C' | 'X' | 'I'

Для проверки и интерпретации строки используется иерархия классов с общим базовым классом RNInterpreter, имеющим 4 под-интерпретатора. Каждый под-интерпретатор получает "контекст" (оставшуюся неразобранную часть строки и накопленное вычисленное значение разобранной части) и вносит свой вклад в процесс обработки. Под-переводчики просто определяют шаблонные методы, объявленные в базовом классе RNInterpreter.

#include <iostream.h>

#include <string.h>

class Thousand;

class Hundred;

class Ten;

class One;

class RNInterpreter{

 public:

   RNInterpreter(); // ctor for client

   RNInterpreter(int){}

   // ctor for subclasses, avoids infinite loop

   int interpret(char*); // interpret() for client

   virtual void interpret(char *input, int &total)    {

       // for internal use

       int index;

       index = 0;

       if (!strncmp(input, nine(), 2))        {

           total += 9 * multiplier();

           index += 2;        }

       else if (!strncmp(input, four(), 2))        {

           total += 4 * multiplier();

           index += 2;        }        else        {

           if (input[0] == five())            {

               total += 5 * multiplier();

               index = 1;            }

           else

             index = 0;

           for (int end = index + 3; index < end; index++)

             if (input[index] == one())

               total += 1 * multiplier();

             else

               break;        }

       strcpy(input, &(input[index]));

   } // remove leading chars processed

 protected:

   // cannot be pure virtual because client asks for instance

   virtual char one(){}

   virtual char *four(){}

   virtual char five(){}

   virtual char *nine(){}

   virtual int multiplier(){}

 private:

   RNInterpreter *thousands;

   RNInterpreter *hundreds;

   RNInterpreter *tens;

   RNInterpreter *ones;};

class Thousand: public RNInterpreter{

 public:

   // provide 1-arg ctor to avoid infinite loop in base class ctor

   Thousand(int): RNInterpreter(1){}

 protected:

   char one()    {

       return 'M';    }

   char *four()    {

       return "";    }

   char five()    {

       return '\0';    }

   char *nine()    {

       return "";    }

   int multiplier()    {

       return 1000;    }};

class Hundred: public RNInterpreter{

 public:

   Hundred(int): RNInterpreter(1){}

 protected:

   char one()    {

       return 'C';    }

   char *four()    {

       return "CD";    }

   char five()    {

       return 'D';    }

   char *nine()    {

       return "CM";    }

   int multiplier()    {

       return 100;    }};

class Ten: public RNInterpreter{

 public:

   Ten(int): RNInterpreter(1){}

 protected:

   char one()    {

       return 'X';    }

   char *four()    {

       return "XL";    }

   char five()    {

       return 'L';    }

   char *nine()    {

       return "XC";    }

   int multiplier()    {

       return 10;    }};

class One: public RNInterpreter{

 public:

   One(int): RNInterpreter(1){}

 protected:

   char one()    {

       return 'I';    }

   char *four()    {

       return "IV";    }

   char five()    {

       return 'V';    }

   char *nine()    {

       return "IX";    }

   int multiplier()    {

       return 1;    }};

RNInterpreter::RNInterpreter(){

 // use 1-arg ctor to avoid infinite loop

 thousands = new Thousand(1);

 hundreds = new Hundred(1);

 tens = new Ten(1);

 ones = new One(1);}

int RNInterpreter::interpret(char *input){

 int total;

 total = 0;

 thousands->interpret(input, total);

 hundreds->interpret(input, total);

 tens->interpret(input, total);

 ones->interpret(input, total);

 if (strcmp(input, ""))

 // if input was invalid, return 0

   return 0;

 return total;}

int main(){

 RNInterpreter interpreter;

 char input[20];

 cout << "Enter Roman Numeral: ";

 while (cin >> input)  {

   cout << "   interpretation is "

        << interpreter.interpret(input) << endl;

   cout << "Enter Roman Numeral: ";  }}

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

Enter Roman Numeral: MCMXCVI

  interpretation is 1996

Enter Roman Numeral: MMMCMXCIX

  interpretation is 3999

Enter Roman Numeral: MMMM

  interpretation is 0

Enter Roman Numeral: MDCLXVIIII

  interpretation is 0

Enter Roman Numeral: CXCX

  interpretation is 0

Enter Roman Numeral: MDCLXVI

  interpretation is 1666

Enter Roman Numeral: DCCCLXXXVIII

  interpretation is 888


Паттерн Composite (компоновщик)

Назначение паттерна Composite

Используйте паттерн Composite если:

Необходимо объединять группы схожих объектов и управлять ими.

Объекты могут быть как примитивными (элементарными), так и составными (сложными). Составной объект может включать в себя коллекции других объектов, образуя сложные древовидные структуры. Пример: директория файловой системы состоит из элементов, каждый их которых также может быть директорией.

Код клиента работает с примитивными и составными объектами единообразно.

Описание паттерна Composite

Управление группами объектов может быть непростой задачей, особенно, если эти объекты содержат собственные объекты.

Для военной стратегической игры ”Пунические войны ”, описывающей военное противостояние между Римом и Карфагеном (см. раздел Порождающие паттерны), каждая боевая единица (всадник, лучник, пехотинец) имеет свою собственную разрушающую силу. Эти единицы могут объединяться в группы для образования более сложных военных подразделений, например, римские легионы, которые, в свою очередь, объединяясь, образуют целую армию. Как рассчитать боевую мощь таких иерархических соединений?

Паттерн Composite предлагает следующее решение. Он вводит абстрактный базовый класс Component с поведением, общим для всех примитивных и составных объектов. Для случая стратегической игры - это метод getStrength() для подсчета разрушающей силы. Подклассы Primitive and Composite являются производными от класса Component. Составной объект Composite хранит компоненты-потомки абстрактного типа Component, каждый из которых может быть также Composite.

UML-диаграмма классов паттерна Composite

Для добавления или удаления объектов-потомков в составной объект Composite, класс Component определяет интерфейсы add() и remove().

Реализация паттерна Composite

Применим паттерн Composite для нашей стратегической игры. Сначала сформируем различные военные соединения римской армии, а затем рассчитаем разрушающую силу.

#include <iostream>

#include <vector>

#include <assert.h>

 

// Component

class Unit

{

 public:

   virtual int getStrength() = 0;

   virtual void addUnit(Unit* p) {

     assert( false);

   }

   virtual ~Unit() {}

};

 

// Primitives

class Archer: public Unit

{

 public:

   virtual int getStrength() {

     return 1;

   }

};

 

class Infantryman: public Unit

{

 public:

   virtual int getStrength() {

     return 2;

   }

};

 

class Horseman: public Unit

{

 public:    

   virtual int getStrength() {

     return 3;

   }

};

 

 

// Composite

class CompositeUnit: public Unit

{

 public:

   int getStrength() {

     int total = 0;

     for(int i=0; i<c.size(); ++i)

       total += c[i]->getStrength();

     return total;

   }

   void addUnit(Unit* p) {

       c.push_back( p);

   }

   ~CompositeUnit() {

     for(int i=0; i<c.size(); ++i)

       delete c[i];

   }

 private:    

  std::vector<Unit*> c;

};

 

 

// Вспомогательная функция для создания легиона

CompositeUnit* createLegion()

{

 // Римский легион содержит:

 CompositeUnit* legion = new CompositeUnit;

 // 3000 тяжелых пехотинцев

 for (int i=0; i<3000; ++i)

   legion->addUnit(new Infantryman);

 // 1200 легких пехотинцев

 for (int i=0; i<1200; ++i)

   legion->addUnit(new Archer);

 // 300 всадников

 for (int i=0; i<300; ++i)

   legion->addUnit(new Horseman);

 

 return legion;

}

 

int main()

{    

 // Римская армия состоит из 4-х легионов

 CompositeUnit* army = new CompositeUnit;  

 for (int i=0; i<4; ++i)

   army->addUnit( createLegion());

 

 cout << "Roman army damaging strength is "

      << army->getStrength() << endl;

 // …

 delete army;

 return 0;

}

Следует обратить внимание на один важный момент. Абстрактный базовый класс Unit объявляет интерфейс для добавления новых боевых единиц addUnit(), несмотря на то, что объектам примитивных типов (Archer, Infantryman, Horseman) подобная операция не нужна. Сделано это в угоду прозрачности системы в ущерб ее безопасности. Клиент знает, что объект типа Unit всегда будет иметь метод addUnit(). Однако его вызов для примитивных объектов считается ошибочным и небезопасным.

Можно сделать систему более безопасной, переместив метод addUnit() в составной объект CompositeUnit. Однако при этом возникает следующая проблема: мы не знаем, содержит ли объект Unit метод addUnit().

Рассмотрим следующий фрагмент кода.

class Unit

{

 public:

   virtual CompositeUnit* getComposite() {

     return 0;

   }

   // …

};

 

// Composite

class CompositeUnit: public Unit

{

 public:

  void addUnit(Unit* p);

   CompositeUnit* getComposite() {

     return this;

   }

   // …

};

В абстрактном базовом классе Unit появился новый виртуальный метод getComposite() с реализацией по умолчанию, которая возвращает 0. Класс CompositeUnit переопределяет этот метод, возвращая указатель на самого себя. Благодаря этому методу можно запросить у компонента его тип. Если он составной, то можно применить операцию addUnit().

if (unit->getComposite())

{

  unit->getComposite()->addUnit( new Archer);

}

Результаты применения паттерна Composite

Достоинства паттерна Composite

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

Код клиента имеет простую структуру – примитивные и составные объекты обрабатываются одинаковым образом.

Паттерн Composite позволяет легко обойти все узлы древовидной структуры

Недостатки паттерна Composite

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




1. Ester (Пасха)
2. Особенности заключения договора консигнации с иностранным партнеро
3. Стагнация в сфере развития мирного атома продолжается Ветроэнергетика бурно развивается
4. Moscow
5. Д. Примите решение по ситуации и обоснуйте его.html
6. Основы закаливания 001
7. Анализ деятельности ЗАО Стройкомплекс
8. Экологическая экспертиза и предупреждение негативного воздействия на окружающую среду
9. Курсовая работа- Дифференциальная диагностика стертой дизартрии и дислалии
10. вити ще трохиуяви уявити наскільки та леки від нас зірки уявити щотуманний пояс Чумацького Шлях
11. ТЕМАТИКА И КАЛЕНДАРНЫЙ ПЛАН ЛЕКЦИЙ
12. Срак работающий дворником как всегда делал свою работу
13. Материализм в учении древнегреческих атомистов
14. Реферат- Методология исследования соотношения семейных и внесемейных ценностных ориентаций
15. логическое устройство- структура назначение Информация от лат
16. Совершенствовать навыки и умения детей в аппликации
17. Йорк Мальдивы ЛасВегас Париж Весь мир Ваш покупаю что хочу живу в хорошем доме или квартире езжу на маш
18.  Деятельность- сущность и основные типы
19. Корекційна освіта Освітньокваліфікаційний рівень- спеціаліст.
20. Описание работы электрической схемы охранного устройства с автодозвоном по телефонной линии