Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Диаграммы




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

UML 2.x

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.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 используются следующие виды диаграмм (для исключения неоднозначности приведены также обозначения на английском языке):

 

Структурные диаграммы: · Диаграмма классов · Диаграмма компонентов · Композитной/составной структуры · Диаграмма кооперации (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 (интерпетатор)

Назначение паттерна 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 объектов определенных типов. Так, например, в состав римской армии не могут входить боевые слоны.




Поделиться с друзьями:


Дата добавления: 2015-05-22; Просмотров: 1132; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.012 сек.