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

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


Скачать 1.98 Mb.
НазваниеDesignPatternsphp documentation
АнкорПатерны программирования
Дата06.02.2023
Размер1.98 Mb.
Формат файлаpdf
Имя файлаdesignpatternsphp-readthedocs-io-ru-latest.pdf
ТипДокументы
#923605
страница4 из 9
1   2   3   4   5   6   7   8   9
;
32
}
33 34
final public static function get
(string
$key
)
:
Service
35
{
36
if
(
!
in_array
(
$key
, self
::
$allowedKeys
)
|| !
isset
(self
::
$services
[
$key
])) {
37
throw new
InvalidArgumentException(
'Invalid key given'
);
38
}
39 40
return self
::
$services
[
$key
];
41
}
42
}
Service.php
1
2
(continues on next page)
74
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
3
namespace
DesignPatterns\Structural\Registry;
4 5
class
Service
6
{
7 8
}
Тест
Tests/RegistryTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Registry\Tests;
6 7
use
InvalidArgumentException;
8
use
DesignPatterns\Structural\Registry\Registry;
9
use
DesignPatterns\Structural\Registry\Service;
10
use
PHPUnit\Framework\TestCase;
11 12
class
RegistryTest extends
TestCase
13
{
14
private
Service
$service
;
15 16
protected function setUp
()
:
void
17
{
18
$this
->
service
=
$this
->
getMockBuilder
(Service
::
class
)
->
getMock
();
19
}
20 21
public function testSetAndGetLogger
()
22
{
23
Registry
::
set
(Registry
::
LOGGER
,
$this
->
service
);
24 25
$this
->
assertSame
(
$this
->
service
, Registry
::
get
(Registry
::
LOGGER
));
26
}
27 28
public function testThrowsExceptionWhenTryingToSetInvalidKey
()
29
{
30
$this
->
expectException
(InvalidArgumentException
::
class
);
31 32
Registry
::
set
(
'foobar'
,
$this
->
service
);
33
}
34 35
/**
36
* notice @runInSeparateProcess here: without it, a previous test might have set it

˓→
already and
37
* testing would not be possible. That's why you should implement Dependency

˓→
Injection where an
38
* injected class may easily be replaced by a mockup
(continues on next page)
1.2. Структурные шаблоны проектирования (Structural)
75

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
39
*
40
* @runInSeparateProcess
41
*/
42
public function testThrowsExceptionWhenTryingToGetNotSetKey
()
43
{
44
$this
->
expectException
(InvalidArgumentException
::
class
);
45 46
Registry
::
get
(Registry
::
LOGGER
);
47
}
48
}
1.3 Поведенческие шаблоны проектирования (Behavioral)
Поведенческие шаблоны проектирования определяют общие закономерности связей между объектами,
реализующими данные паттерны. Следование этим шаблонам уменьшает связность системы и облег- чает коммуникацию между объектами, что улучшает гибкость программного продукта.
1.3.1 Цепочка Обязанностей (Chain Of Responsibilities)
Назначение
Построить цепочку объектов для обработки вызова в последовательном порядке. Если один объект не может справиться с вызовом, он делегирует вызов следующему в цепи и так далее.
Примеры
фреймворк для записи журналов, где каждый элемент цепи самостоятельно принимает решение,
что делать с сообщением для логирования.
• фильтр спама
• кеширование: первый объект является экземпляром, к примеру, интерфейса Memcached. Если запись в кеше отсутствует, вызов делегируется интерфейсу базы данных.
76
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Диаграмма UML
Код
Вы можете найти этот код на
GitHub
Handler.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\ChainOfResponsibilities;
6 7
use
Psr\Http\Message\RequestInterface;
8 9
abstract class
Handler
10
{
11
public function
__construct
(
private
?
Handler
$successor
=
null
)
12
{
13
}
14 15
/**
16
* This approach by using a template method pattern ensures you that
17
* each subclass will not forget to call the successor
18
*/
19
final public function handle
(RequestInterface
$request
)
: ?
string
20
{
21
$processed
=
$this
->
processing
(
$request
);
22 23
if
(
$processed
===
null
&&
$this
->
successor
!==
null
) {
24
// the request has not been processed by this handler => see the next
25
$processed
=
$this
->
successor
->
handle
(
$request
);
26
}
(continues on next page)
1.3. Поведенческие шаблоны проектирования (Behavioral)
77

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
27 28
return
$processed
;
29
}
30 31
abstract protected function processing
(RequestInterface
$request
)
: ?
string;
32
}
Responsible/FastStorage.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible;
6 7
use
DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
8
use
Psr\Http\Message\RequestInterface;
9 10
class
HttpInMemoryCacheHandler extends
Handler
11
{
12
public function
__construct
(
private array
$data
,
?
Handler
$successor
=
null
)
13
{
14
parent
::
__construct
(
$successor
);
15
}
16 17
protected function processing
(RequestInterface
$request
)
: ?
string
18
{
19
$key
=
sprintf
(
20
'%s?%s'
,
21
$request
->
getUri
()
->
getPath
(),
22
$request
->
getUri
()
->
getQuery
()
23
);
24 25
if
(
$request
->
getMethod
()
==
'GET'
&&
isset
(
$this
->
data
[
$key
])) {
26
return
$this
->
data
[
$key
];
27
}
28 29
return null
;
30
}
31
}
Responsible/SlowStorage.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible;
6 7
use
DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
8
use
Psr\Http\Message\RequestInterface;
9
(continues on next page)
78
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
10
class
SlowDatabaseHandler extends
Handler
11
{
12
protected function processing
(RequestInterface
$request
)
: ?
string
13
{
14
// this is a mockup, in production code you would ask a slow (compared to in-
˓→
memory) DB for the results
15 16
return
'Hello World!'
;
17
}
18
}
Тест
Tests/ChainTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\ChainOfResponsibilities\Tests;
6 7
use
DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
8
use
DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\
˓→
HttpInMemoryCacheHandler;
9
use
DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowDatabaseHandler;
10
use
PHPUnit\Framework\TestCase;
11
use
Psr\Http\Message\RequestInterface;
12
use
Psr\Http\Message\UriInterface;
13 14
class
ChainTest extends
TestCase
15
{
16
private
Handler
$chain
;
17 18
protected function setUp
()
:
void
19
{
20
$this
->
chain
=
new
HttpInMemoryCacheHandler(
21
[
'/foo/bar?index=1'
=>
'Hello In Memory!'
],
22
new
SlowDatabaseHandler()
23
);
24
}
25 26
public function testCanRequestKeyInFastStorage
()
27
{
28
$uri
=
$this
->
createMock
(UriInterface
::
class
);
29
$uri
->
method
(
'getPath'
)
->
willReturn
(
'/foo/bar'
);
30
$uri
->
method
(
'getQuery'
)
->
willReturn
(
'index=1'
);
31 32
$request
=
$this
->
createMock
(RequestInterface
::
class
);
33
$request
->
method
(
'getMethod'
)
34
->
willReturn
(
'GET'
);
35
$request
->
method
(
'getUri'
)
->
willReturn
(
$uri
);
(continues on next page)
1.3. Поведенческие шаблоны проектирования (Behavioral)
79

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
36 37
$this
->
assertSame
(
'Hello In Memory!'
,
$this
->
chain
->
handle
(
$request
));
38
}
39 40
public function testCanRequestKeyInSlowStorage
()
41
{
42
$uri
=
$this
->
createMock
(UriInterface
::
class
);
43
$uri
->
method
(
'getPath'
)
->
willReturn
(
'/foo/baz'
);
44
$uri
->
method
(
'getQuery'
)
->
willReturn
(
''
);
45 46
$request
=
$this
->
createMock
(RequestInterface
::
class
);
47
$request
->
method
(
'getMethod'
)
48
->
willReturn
(
'GET'
);
49
$request
->
method
(
'getUri'
)
->
willReturn
(
$uri
);
50 51
$this
->
assertSame
(
'Hello World!'
,
$this
->
chain
->
handle
(
$request
));
52
}
53
}
1.3.2 Команда (Command)
Назначение
Инкапсулировать действие и его параметры
Допустим, у нас есть объекты Invoker (Командир) и Receiver (Исполнитель). Этот паттерн использует реализацию интерфейса «Команда», чтобы вызвать некий метод Исполнителя используя для этого из- вестный Командиру метод «execute()». Командир просто знает, что нужно вызвать метод “execute()”,
для обработки команды клиента, не разбираясь в деталях реализации Исполнителя. Исполнитель от- делен от Командира.
Вторым аспектом этого паттерна является метод undo(), который отменяет действие, выполняемое методом execute(). Команды также могут быть объединены в более общие команды с минимальным копированием-вставкой и полагаясь на композицию поверх наследования.
80
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Примеры
• A text editor : all events are commands which can be undone, stacked and saved.
• большие утилиты для командной строки (например, Vagrant) используют вложенные команды для разделения различных задач и упаковки их в «модули», каждый из которых может быть реализован с помощью паттерна «Команда».
Диаграмма UML
1.3. Поведенческие шаблоны проектирования (Behavioral)
81

DesignPatternsPHP Documentation, Выпуск 1.0
Код
Вы также можете найти этот код на
GitHub
Command.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command;
6 7
interface
Command
8
{
9
/**
10
* this is the most important method in the Command pattern,
11
* The Receiver goes in the constructor.
12
*/
13
public function execute
();
14
}
UndoableCommand.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command;
6 7
interface
UndoableCommand extends
Command
8
{
9
/**
10
* This method is used to undo change made by command execution
11
*/
12
public function undo
();
13
}
HelloCommand.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command;
6 7
/**
8
* This concrete command calls "print" on the Receiver, but an external
9
* invoker just knows that it can call "execute"
10
*/
11
class
HelloCommand implements
Command
12
{
13
/**
14
* Each concrete command is built with different receivers.
15
* There can be one, many or completely no receivers, but there can be other

(continues on next page)
82
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
˓→
commands in the parameters
16
*/
17
public function
__construct
(
private
Receiver
$output
)
18
{
19
}
20 21
/**
22
* execute and output "Hello World".
23
*/
24
public function execute
()
25
{
26
// sometimes, there is no receiver and this is the command which does all the

˓→
work
27
$this
->
output
->
write
(
'Hello World'
);
28
}
29
}
AddMessageDateCommand.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command;
6 7
/**
8
* This concrete command tweaks receiver to add current date to messages
9
* invoker just knows that it can call "execute"
10
*/
11
class
AddMessageDateCommand implements
UndoableCommand
12
{
13
/**
14
* Each concrete command is built with different receivers.
15
* There can be one, many or completely no receivers, but there can be other

˓→
commands in the parameters.
16
*/
17
public function
__construct
(
private
Receiver
$output
)
18
{
19
}
20 21
/**
22
* Execute and make receiver to enable displaying messages date.
23
*/
24
public function execute
()
25
{
26
// sometimes, there is no receiver and this is the command which
27
// does all the work
28
$this
->
output
->
enableDate
();
29
}
30 31
/**
32
* Undo the command and make receiver to disable displaying messages date.
(continues on next page)
1.3. Поведенческие шаблоны проектирования (Behavioral)
83

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
33
*/
34
public function undo
()
35
{
36
// sometimes, there is no receiver and this is the command which
37
// does all the work
38
$this
->
output
->
disableDate
();
39
}
40
}
Receiver.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command;
6 7
/**
8
* Receiver is a specific service with its own contract and can be only concrete.
9
*/
10
class
Receiver
11
{
12
private bool
$enableDate
=
false
;
13 14
/**
15
* @var string[]
16
*/
17
private array
$output
=
[];
18 19
public function write
(string
$str
)
20
{
21
if
(
$this
->
enableDate
) {
22
$str
.=
' ['
date
(
'Y-m-d'
)
']'
;
23
}
24 25
$this
->
output
[]
=
$str
;
26
}
27 28
public function getOutput
()
:
string
29
{
30
return join
(
"\n"
,
$this
->
output
);
31
}
32 33
/**
34
* Enable receiver to display message date
35
*/
36
public function enableDate
()
37
{
38
$this
->
enableDate
=
true
;
39
}
40 41
/**
(continues on next page)
84
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
42
* Disable receiver to display message date
43
*/
44
public function disableDate
()
45
{
46
$this
->
enableDate
=
false
;
47
}
48
}
Invoker.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command;
6 7
/**
8
* Invoker is using the command given to it.
9
* Example : an Application in SF2.
10
*/
11
class
Invoker
12
{
13
private
Command
$command
;
14 15
/**
16
* in the invoker we find this kind of method for subscribing the command
17
* There can be also a stack, a list, a fixed set ...
18
*/
19
public function setCommand
(Command
$cmd
)
20
{
21
$this
->
command
=
$cmd
;
22
}
23 24
/**
25
* executes the command; the invoker is the same whatever is the command
26
*/
27
public function run
()
28
{
29
$this
->
command
->
execute
();
30
}
31
}
1.3. Поведенческие шаблоны проектирования (Behavioral)
85

DesignPatternsPHP Documentation, Выпуск 1.0
Тест
Tests/CommandTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command\Tests;
6 7
use
DesignPatterns\Behavioral\Command\HelloCommand;
8
use
DesignPatterns\Behavioral\Command\Invoker;
9
use
DesignPatterns\Behavioral\Command\Receiver;
10
use
PHPUnit\Framework\TestCase;
11 12
class
CommandTest extends
TestCase
13
{
14
public function testInvocation
()
15
{
16
$invoker
=
new
Invoker();
17
$receiver
=
new
Receiver();
18 19
$invoker
->
setCommand
(
new
HelloCommand(
$receiver
));
20
$invoker
->
run
();
21
$this
->
assertSame
(
'Hello World'
,
$receiver
->
getOutput
());
22
}
23
}
Tests/UndoableCommandTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Behavioral\Command\Tests;
6 7
use
DesignPatterns\Behavioral\Command\AddMessageDateCommand;
8
use
DesignPatterns\Behavioral\Command\HelloCommand;
1   2   3   4   5   6   7   8   9


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