Главная страница

Патерны программирования. DesignPatternsphp documentation


Скачать 1.98 Mb.
НазваниеDesignPatternsphp documentation
АнкорПатерны программирования
Дата06.02.2023
Размер1.98 Mb.
Формат файлаpdf
Имя файлаdesignpatternsphp-readthedocs-io-ru-latest.pdf
ТипДокументы
#923605
страница6 из 9
1   2   3   4   5   6   7   8   9
$user
)
16
{
17
$this
->
ui
->
outputUserInfo
(
$user
);
18
}
19 20
public function getUser
(string
$username
)
:
string
21
{
22
return
$this
->
userRepository
->
getUserName
(
$username
);
23
}
24
}
Тест
Tests/MediatorTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Tests\Mediator\Tests;
6 7
use
DesignPatterns\Behavioral\Mediator\Ui;
(continues on next page)
100
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
8
use
DesignPatterns\Behavioral\Mediator\UserRepository;
9
use
DesignPatterns\Behavioral\Mediator\UserRepositoryUiMediator;
10
use
PHPUnit\Framework\TestCase;
11 12
class
MediatorTest extends
TestCase
13
{
14
public function testOutputHelloWorld
()
15
{
16
$mediator
=
new
UserRepositoryUiMediator(
new
UserRepository(),
new
Ui());
17 18
$this
->
expectOutputString
(
'User: Dominik'
);
19
$mediator
->
printInfoAbout
(
'Dominik'
);
20
}
21
}
1.3.6 Хранитель (Memento)
Назначение
Шаблон предоставляет возможность восстановить объект в его предыдущем состоянии (отменить дей- ствие посредством отката к предыдущему состоянию) или получить доступ к состоянию объекта, не раскрывая его реализацию (т.е. сам объект не обязан иметь функциональность для возврата текущего состояния).
Шаблон Хранитель реализуется тремя объектами: «Создателем» (originator), «Опекуном» (caretaker)
и «Хранитель» (memento).
Хранитель - это объект, который хранит конкретный снимок состояния некоторого объекта или ре- сурса: строки, числа, массива, экземпляра класса и так далее. Уникальность в данном случае подра- зумевает не запрет на существование одинаковых состояний в разных снимках, а то, что состояние можно извлечь в виде независимой копии. Любой объект, сохраняемый в Хранителе, должен быть полной копией исходного объекта, а не ссылкой на исходный объект. Сам объект Хранитель является
«непрозрачным объектом» (тот, который никто не может и не должен изменять).
Создатель — это объект, который содержит в себе актуальное состояние внешнего объекта строго заданного типа и умеет создавать уникальную копию этого состояния, возвращая её, обёрнутую в объ- ект Хранителя. Создатель не знает истории изменений. Создателю можно принудительно установить конкретное состояние извне, которое будет считаться актуальным. Создатель должен позаботиться о том, чтобы это состояние соответствовало типу объекта, с которым ему разрешено работать. Создатель может (но не обязан) иметь любые методы, но они не могут менять сохранённое состояние объекта.
Опекун управляет историей снимков состояний. Он может вносить изменения в объект, принимать решение о сохранении состояния внешнего объекта в Создателе, запрашивать от Создателя снимок текущего состояния, или привести состояние Создателя в соответствие с состоянием какого-то снимка из истории.
1.3. Поведенческие шаблоны проектирования (Behavioral)
101

DesignPatternsPHP Documentation, Выпуск 1.0
Примеры

Зерно генератора псевдослучайных чисел.
• Состояние конечного автомата
• Контроль промежуточных состояний модели в
ORM
перед сохранением
Диаграмма UML
102
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Код
Вы можете найти этот код на
GitHub
Memento.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Memento;
6 7
class
Memento
8
{
9
public function
__construct
(
private
State
$state
)
10
{
11
}
12 13
public function getState
()
:
State
14
{
15
return
$this
->
state
;
16
}
17
}
State.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Memento;
6 7
use
InvalidArgumentException;
8 9
class
State implements
\Stringable
10
{
11
public const
STATE_CREATED
=
'created'
;
12
public const
STATE_OPENED
=
'opened'
;
13
public const
STATE_ASSIGNED
=
'assigned'
;
14
public const
STATE_CLOSED
=
'closed'
;
15 16
private string
$state
;
17 18
/**
19
* @var string[]
20
*/
21
private static array
$validStates
=
[
22
self
::
STATE_CREATED
,
23
self
::
STATE_OPENED
,
24
self
::
STATE_ASSIGNED
,
25
self
::
STATE_CLOSED
,
26
];
27 28
public function
__construct
(string
$state
)
(continues on next page)
1.3. Поведенческие шаблоны проектирования (Behavioral)
103

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
29
{
30
self
::
ensureIsValidState
(
$state
);
31 32
$this
->
state
=
$state
;
33
}
34 35
private static function ensureIsValidState
(string
$state
)
36
{
37
if
(
!
in_array
(
$state
, self
::
$validStates
)) {
38
throw new
InvalidArgumentException(
'Invalid state given'
);
39
}
40
}
41 42
public function
__toString
()
:
string
43
{
44
return
$this
->
state
;
45
}
46
}
Ticket.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Memento;
6 7
/**
8
* Ticket is the "Originator" in this implementation
9
*/
10
class
Ticket
11
{
12
private
State
$currentState
;
13 14
public function
__construct
()
15
{
16
$this
->
currentState
=
new
State(State
::
STATE_CREATED
);
17
}
18 19
public function open
()
20
{
21
$this
->
currentState
=
new
State(State
::
STATE_OPENED
);
22
}
23 24
public function assign
()
25
{
26
$this
->
currentState
=
new
State(State
::
STATE_ASSIGNED
);
27
}
28 29
public function close
()
30
{
31
$this
->
currentState
=
new
State(State
::
STATE_CLOSED
);
(continues on next page)
104
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
32
}
33 34
public function saveToMemento
()
:
Memento
35
{
36
return new
Memento(
clone
$this
->
currentState
);
37
}
38 39
public function restoreFromMemento
(Memento
$memento
)
40
{
41
$this
->
currentState
=
$memento
->
getState
();
42
}
43 44
public function getState
()
:
State
45
{
46
return
$this
->
currentState
;
47
}
48
}
Тест
Tests/MementoTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Memento\Tests;
6 7
use
DesignPatterns\Behavioral\Memento\State;
8
use
DesignPatterns\Behavioral\Memento\Ticket;
9
use
PHPUnit\Framework\TestCase;
10 11
class
MementoTest extends
TestCase
12
{
13
public function testOpenTicketAssignAndSetBackToOpen
()
14
{
15
$ticket
=
new
Ticket();
16 17
// open the ticket
18
$ticket
->
open
();
19
$openedState
=
$ticket
->
getState
();
20
$this
->
assertSame
(State
::
STATE_OPENED
, (string)
$ticket
->
getState
());
21 22
$memento
=
$ticket
->
saveToMemento
();
23 24
// assign the ticket
25
$ticket
->
assign
();
26
$this
->
assertSame
(State
::
STATE_ASSIGNED
, (string)
$ticket
->
getState
());
27 28
// now restore to the opened state, but verify that the state object has been

˓→
cloned for the memento
(continues on next page)
1.3. Поведенческие шаблоны проектирования (Behavioral)
105

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
29
$ticket
->
restoreFromMemento
(
$memento
);
30 31
$this
->
assertSame
(State
::
STATE_OPENED
, (string)
$ticket
->
getState
());
32
$this
->
assertNotSame
(
$openedState
,
$ticket
->
getState
());
33
}
34
}
1.3.7 Объект Null (Null Object)
Назначение
NullObject не шаблон из книги Банды Четырёх, но схема, которая появляется достаточно часто, чтобы считаться паттерном. Она имеет следующие преимущества:
Клиентский код упрощается
• Уменьшает шанс исключений из-за нулевых указателей (и ошибок PHP различного уровня)
• Меньше дополнительных условий — значит меньше тесткейсов
Методы, которые возвращают объект или Null, вместо этого должны вернуть объект NullObject.
Это упрощённый формальный код, устраняющий необходимость проверки if (!is_null($obj)) {
$obj->callSomething(); }, заменяя её на обычный вызов $obj->callSomething();.
Примеры
• Null logger or null output to preserve a standard way of interaction between objects, even if the shouldn’t do anything
• null handler in a Chain of Responsibilities pattern
• null command in a Command pattern
106
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Диаграмма UML
1.3. Поведенческие шаблоны проектирования (Behavioral)
107

DesignPatternsPHP Documentation, Выпуск 1.0
Код
Вы можете найти этот код на
GitHub
Service.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\NullObject;
6 7
class
Service
8
{
9
public function
__construct
(
private
Logger
$logger
)
10
{
11
}
12 13
/**
14
* do something ...
15
*/
16
public function doSomething
()
17
{
18
// notice here that you don't have to check if the logger is set with eg. is_
˓→
null(), instead just use it
19
$this
->
logger
->
log
(
'We are in '
__METHOD__
);
20
}
21
}
Logger.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\NullObject;
6 7
/**
8
* Key feature: NullLogger must inherit from this interface like any other loggers
9
*/
10
interface
Logger
11
{
12
public function log
(string
$str
);
13
}
PrintLogger.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\NullObject;
6 7
class
PrintLogger implements
Logger
(continues on next page)
108
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
8
{
9
public function log
(string
$str
)
10
{
11
echo
$str
;
12
}
13
}
NullLogger.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\NullObject;
6 7
class
NullLogger implements
Logger
8
{
9
public function log
(string
$str
)
10
{
11
// do nothing
12
}
13
}
Тест
Tests/LoggerTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\NullObject\Tests;
6 7
use
DesignPatterns\Behavioral\NullObject\NullLogger;
8
use
DesignPatterns\Behavioral\NullObject\PrintLogger;
9
use
DesignPatterns\Behavioral\NullObject\Service;
10
use
PHPUnit\Framework\TestCase;
11 12
class
LoggerTest extends
TestCase
13
{
14
public function testNullObject
()
15
{
16
$service
=
new
Service(
new
NullLogger());
17
$this
->
expectOutputString
(
''
);
18
$service
->
doSomething
();
19
}
20 21
public function testStandardLogger
()
22
{
23
$service
=
new
Service(
new
PrintLogger());
24
$this
->
expectOutputString
(
'We are in DesignPatterns\Behavioral\NullObject\
(continues on next page)
1.3. Поведенческие шаблоны проектирования (Behavioral)
109

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
˓→
Service::doSomething'
);
25
$service
->
doSomething
();
26
}
27
}
1.3.8 Наблюдатель (Observer)
Назначение
Для реализации публикации/подписки на поведение объекта, всякий раз, когда объект «Subject» ме- няет свое состояние, прикрепленные объекты «Observers» будут уведомлены. Паттерн используется,
чтобы сократить количество связанных напрямую объектов и вместо этого использует слабую связь
(loose coupling).
Примеры
• Система очереди сообщений наблюдает за очередями, чтобы отображать прогресс в GUI
Примечание
PHP предоставляет два стандартных интерфейса, которые могут помочь реализовать этот шаблон:
SplObserver и SplSubject.
Диаграмма UML
110
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Код
Вы можете найти этот код на
GitHub
User.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Observer;
6 7
use
SplSubject;
8
use
SplObjectStorage;
9
use
SplObserver;
10 11
/**
12
* User implements the observed object (called Subject), it maintains a list of

˓→
observers and sends notifications to
13
* them in case changes are made on the User object
14
*/
15
class
User implements
SplSubject
16
{
17
private
SplObjectStorage
$observers
;
18
private
$email
;
19 20
public function
__construct
()
21
{
22
$this
->
observers
=
new
SplObjectStorage();
23
}
24 25
public function attach
(SplObserver
$observer
)
:
void
26
{
27
$this
->
observers
->
attach
(
$observer
);
28
}
29 30
public function detach
(SplObserver
$observer
)
:
void
31
{
32
$this
->
observers
->
detach
(
$observer
);
33
}
34 35
public function changeEmail
(string
$email
)
:
void
36
{
37
$this
->
email
=
$email
;
38
$this
->
notify
();
39
}
40 41
public function notify
()
:
void
42
{
43
/** @var SplObserver $observer */
44
foreach
(
$this
->
observers as
$observer
) {
45
$observer
->
update
(
$this
);
46
}
47
}
(continues on next page)
1.3. Поведенческие шаблоны проектирования (Behavioral)
111

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
48
}
UserObserver.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Observer;
6 7
use
SplObserver;
8
use
SplSubject;
9 10
class
UserObserver implements
SplObserver
11
{
12
/**
13
* @var SplSubject[]
14
*/
15
private array
$changedUsers
=
[];
16 17
/**
18
* It is called by the Subject, usually by SplSubject::notify()
19
*/
20
public function update
(SplSubject
$subject
)
:
void
21
{
22
$this
->
changedUsers
[]
=
clone
$subject
;
23
}
24 25
/**
26
* @return SplSubject[]
27
*/
28
public function getChangedUsers
()
:
array
29
{
30
return
$this
->
changedUsers
;
31
}
32
}
Тест
Tests/ObserverTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Observer\Tests;
6 7
use
DesignPatterns\Behavioral\Observer\User;
8
use
DesignPatterns\Behavioral\Observer\UserObserver;
9
use
PHPUnit\Framework\TestCase;
10
(continues on next page)
112
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
11
class
ObserverTest extends
TestCase
12
{
13
public function testChangeInUserLeadsToUserObserverBeingNotified
()
14
{
15
$observer
=
new
UserObserver();
16 17
$user
=
new
User();
18
$user
->
attach
(
$observer
);
19 20
$user
->
changeEmail
(
'foo@bar.com'
);
21
$this
->
assertCount
(
1
,
$observer
->
getChangedUsers
());
22
}
23
}
1.3.9 Спецификация (Specification)
Назначение
Строит ясное описание бизнес-правил, на соответствие которым могут быть проверены объекты. Ком- позитный класс спецификация имеет один метод, называемый isSatisfiedBy, который возвращает истину или ложь в зависимости от того, удовлетворяет ли данный объект спецификации.
Примеры

RulerZ
Диаграмма UML
1.3. Поведенческие шаблоны проектирования (Behavioral)
113

DesignPatternsPHP Documentation, Выпуск 1.0
Код
Вы можете найти этот код на
GitHub
Item.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Specification;
6 7
class
Item
8
{
9
public function
__construct
(
private float
$price
)
10
{
11
}
12 13
public function getPrice
()
:
float
14
{
15
return
$this
->
price
;
16
}
17
}
Specification.php
1
2 3
declare
(strict_types
1   2   3   4   5   6   7   8   9


написать администратору сайта