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

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


Скачать 1.98 Mb.
НазваниеDesignPatternsphp documentation
АнкорПатерны программирования
Дата06.02.2023
Размер1.98 Mb.
Формат файлаpdf
Имя файлаdesignpatternsphp-readthedocs-io-ru-latest.pdf
ТипДокументы
#923605
страница2 из 9
1   2   3   4   5   6   7   8   9
'
;
12
}
13
}
TextElement.php
44
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0 1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Composite;
6 7
class
TextElement implements
Renderable
8
{
9
public function
__construct
(
private string
$text
)
10
{
11
}
12 13
public function render
()
:
string
14
{
15
return
$this
->
text
;
16
}
17
}
Тест
Tests/CompositeTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Composite\Tests;
6 7
use
DesignPatterns\Structural\Composite\Form;
8
use
DesignPatterns\Structural\Composite\TextElement;
9
use
DesignPatterns\Structural\Composite\InputElement;
10
use
PHPUnit\Framework\TestCase;
11 12
class
CompositeTest extends
TestCase
13
{
14
public function testRender
()
15
{
16
$form
=
new
Form();
17
$form
->
addElement
(
new
TextElement(
'Email:'
));
18
$form
->
addElement
(
new
InputElement());
19
$embed
=
new
Form();
20
$embed
->
addElement
(
new
TextElement(
'Password:'
));
21
$embed
->
addElement
(
new
InputElement());
22
$form
->
addElement
(
$embed
);
23 24
// This is just an example, in a real world scenario it is important to remember

˓→
that web browsers do not
25
// currently support nested forms
26 27
$this
->
assertSame
(
28
'
Email:Password:

˓→
'
,
(continues on next page)
1.2. Структурные шаблоны проектирования (Structural)
45

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
29
$form
->
render
()
30
);
31
}
32
}
1.2.4 Преобразователь Данных (Data Mapper)
Назначение
Преобразователь Данных — это паттерн, который выступает в роли посредника для двунаправлен- ной передачи данных между постоянным хранилищем данных (часто, реляционной базы данных) и представления данных в памяти (слой домена, то что уже загружено и используется для логической обработки). Цель паттерна в том, чтобы держать представление данных в памяти и постоянное хра- нилище данных независимыми друг от друга и от самого преобразователя данных. Слой состоит из одного или более mapper-а (или объектов доступа к данным), отвечающих за передачу данных. Реа- лизации mapper-ов различаются по назначению. Общие mapper-ы могут обрабатывать всевозоможные типы сущностей доменов, а выделенные mapper-ы будет обрабатывать один или несколько конкретных типов.
Ключевым моментом этого паттерна, в отличие от Активной Записи (Active Records) является то, что модель данных следует
Принципу Единой Обязанности
SOLID.
Примеры
• DB Object Relational Mapper (ORM) : Doctrine2 использует DAO под названием
«EntityRepository»
46
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Диаграмма UML
Код
Вы можете найти этот код на
GitHub
User.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\DataMapper;
6 7
class
User
8
{
9
public static function fromState
(
array
$state
)
:
User
10
{
(continues on next page)
1.2. Структурные шаблоны проектирования (Structural)
47

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
11
// validate state before accessing keys!
12 13
return new self(
14
$state
[
'username'
],
15
$state
[
'email'
]
16
);
17
}
18 19
public function
__construct
(
private string
$username
,
private string
$email
)
20
{
21
}
22 23
public function getUsername
()
:
string
24
{
25
return
$this
->
username
;
26
}
27 28
public function getEmail
()
:
string
29
{
30
return
$this
->
email
;
31
}
32
}
UserMapper.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\DataMapper;
6 7
use
InvalidArgumentException;
8 9
class
UserMapper
10
{
11
public function
__construct
(
private
StorageAdapter
$adapter
)
12
{
13
}
14 15
/**
16
* finds a user from storage based on ID and returns a User object located
17
* in memory. Normally this kind of logic will be implemented using the Repository

˓→
pattern.
18
* However the important part is in mapRowToUser() below, that will create a

˓→
business object from the
19
* data fetched from storage
20
*/
21
public function findById
(int
$id
)
:
User
22
{
23
$result
=
$this
->
adapter
->
find
(
$id
);
24 25
if
(
$result
===
null
) {
(continues on next page)
48
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
26
throw new
InvalidArgumentException(
"User #
$id not found"
);
27
}
28 29
return
$this
->
mapRowToUser
(
$result
);
30
}
31 32
private function mapRowToUser
(
array
$row
)
:
User
33
{
34
return
User
::
fromState
(
$row
);
35
}
36
}
StorageAdapter.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\DataMapper;
6 7
class
StorageAdapter
8
{
9
public function
__construct
(
private array
$data
)
10
{
11
}
12 13
/**
14
* @return array|null
15
*/
16
public function find
(int
$id
)
17
{
18
if
(
isset
(
$this
->
data
[
$id
])) {
19
return
$this
->
data
[
$id
];
20
}
21 22
return null
;
23
}
24
}
Тест
Tests/DataMapperTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\DataMapper\Tests;
6 7
use
InvalidArgumentException;
8
use
DesignPatterns\Structural\DataMapper\StorageAdapter;
(continues on next page)
1.2. Структурные шаблоны проектирования (Structural)
49

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
9
use
DesignPatterns\Structural\DataMapper\User;
10
use
DesignPatterns\Structural\DataMapper\UserMapper;
11
use
PHPUnit\Framework\TestCase;
12 13
class
DataMapperTest extends
TestCase
14
{
15
public function testCanMapUserFromStorage
()
16
{
17
$storage
=
new
StorageAdapter([
1
=>
[
'username'
=>
'domnikl'
,
'email'
=>
˓→
'liebler.dominik@gmail.com'
]]);
18
$mapper
=
new
UserMapper(
$storage
);
19 20
$user
=
$mapper
->
findById
(
1
);
21 22
$this
->
assertInstanceOf
(User
::
class
,
$user
);
23
}
24 25
public function testWillNotMapInvalidData
()
26
{
27
$this
->
expectException
(InvalidArgumentException
::
class
);
28 29
$storage
=
new
StorageAdapter([]);
30
$mapper
=
new
UserMapper(
$storage
);
31 32
$mapper
->
findById
(
1
);
33
}
34
}
1.2.5 Декоратор (Decorator)
Назначение
Динамически добавляет новую функциональность в экземпляры классов.
Примеры
• Web Service Layer: Декораторы JSON и XML для REST сервисов (в этом случае, конечно, только один из них может быть разрешен).
50
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Диаграмма UML
Код
Вы можете найти этот код на
GitHub
Booking.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Decorator;
6 7
interface
Booking
8
{
9
public function calculatePrice
()
:
int;
10 11
public function getDescription
()
:
string;
12
}
BookingDecorator.php
1.2. Структурные шаблоны проектирования (Structural)
51

DesignPatternsPHP Documentation, Выпуск 1.0 1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Decorator;
6 7
abstract class
BookingDecorator implements
Booking
8
{
9
public function
__construct
(
protected
Booking
$booking
)
10
{
11
}
12
}
DoubleRoomBooking.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Decorator;
6 7
class
DoubleRoomBooking implements
Booking
8
{
9
public function calculatePrice
()
:
int
10
{
11
return
40
;
12
}
13 14
public function getDescription
()
:
string
15
{
16
return
'double room'
;
17
}
18
}
ExtraBed.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Decorator;
6 7
class
ExtraBed extends
BookingDecorator
8
{
9
private const
PRICE
=
30
;
10 11
public function calculatePrice
()
:
int
12
{
13
return
$this
->
booking
->
calculatePrice
()
+
self
::
PRICE
;
14
}
15 16
public function getDescription
()
:
string
17
{
(continues on next page)
52
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
18
return
$this
->
booking
->
getDescription
()
' with extra bed'
;
19
}
20
}
WiFi.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Decorator;
6 7
class
WiFi extends
BookingDecorator
8
{
9
private const
PRICE
=
2
;
10 11
public function calculatePrice
()
:
int
12
{
13
return
$this
->
booking
->
calculatePrice
()
+
self
::
PRICE
;
14
}
15 16
public function getDescription
()
:
string
17
{
18
return
$this
->
booking
->
getDescription
()
' with wifi'
;
19
}
20
}
Тест
Tests/DecoratorTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\Decorator\Tests;
6 7
use
DesignPatterns\Structural\Decorator\DoubleRoomBooking;
8
use
DesignPatterns\Structural\Decorator\ExtraBed;
9
use
DesignPatterns\Structural\Decorator\WiFi;
10
use
PHPUnit\Framework\TestCase;
11 12
class
DecoratorTest extends
TestCase
13
{
14
public function testCanCalculatePriceForBasicDoubleRoomBooking
()
15
{
16
$booking
=
new
DoubleRoomBooking();
17 18
$this
->
assertSame
(
40
,
$booking
->
calculatePrice
());
19
$this
->
assertSame
(
'double room'
,
$booking
->
getDescription
());
20
}
(continues on next page)
1.2. Структурные шаблоны проектирования (Structural)
53

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
21 22
public function testCanCalculatePriceForDoubleRoomBookingWithWiFi
()
23
{
24
$booking
=
new
DoubleRoomBooking();
25
$booking
=
new
WiFi(
$booking
);
26 27
$this
->
assertSame
(
42
,
$booking
->
calculatePrice
());
28
$this
->
assertSame
(
'double room with wifi'
,
$booking
->
getDescription
());
29
}
30 31
public function testCanCalculatePriceForDoubleRoomBookingWithWiFiAndExtraBed
()
32
{
33
$booking
=
new
DoubleRoomBooking();
34
$booking
=
new
WiFi(
$booking
);
35
$booking
=
new
ExtraBed(
$booking
);
36 37
$this
->
assertSame
(
72
,
$booking
->
calculatePrice
());
38
$this
->
assertSame
(
'double room with wifi with extra bed'
,
$booking
->
˓→
getDescription
());
39
}
40
}
1.2.6 Внедрение Зависимости (Dependency Injection)
Назначение
Для реализации слабосвязанной архитектуры. Чтобы получить более тестируемый, сопровождаемый и расширяемый код.
Использование
Объект DatabaseConfiguration внедряется в DatabaseConnection и последний получает всё, что ему необходимо из переменной $ config. Без DI, конфигурация будет создана непосредственно в
Connection, что не очень хорошо для тестирования и расширения Connection, так как связывает эти классы напрямую.
Примеры
• The Doctrine2 ORM использует Внедрение Зависимости например для конфигурации, которая внедряется в объект Connection. Для целей тестирования, можно легко создать макет объекта конфигурации и внедрить его в объект Connection, подменив оригинальный.
• Во многих фреймворках уже имеются контейнеры для DI, которые создают объекты через массив с конфигурацией и внедряют туда, где это нужно (например в Контроллеры).
54
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Диаграмма UML
1.2. Структурные шаблоны проектирования (Structural)
55

DesignPatternsPHP Documentation, Выпуск 1.0
Код
Вы можете найти этот код на
GitHub
DatabaseConfiguration.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\DependencyInjection;
6 7
class
DatabaseConfiguration
8
{
9
public function
__construct
(
10
private string
$host
,
11
private int
$port
,
12
private string
$username
,
13
private string
$password
14
) {
15
}
16 17
public function getHost
()
:
string
18
{
19
return
$this
->
host
;
20
}
21 22
public function getPort
()
:
int
23
{
24
return
$this
->
port
;
25
}
26 27
public function getUsername
()
:
string
28
{
29
return
$this
->
username
;
30
}
31 32
public function getPassword
()
:
string
33
{
34
return
$this
->
password
;
35
}
36
}
DatabaseConnection.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\DependencyInjection;
6 7
class
DatabaseConnection
8
{
9
public function
__construct
(
private
DatabaseConfiguration
$configuration
)
(continues on next page)
56
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
(продолжение с предыдущей страницы)
10
{
11
}
12 13
public function getDsn
()
:
string
14
{
15
// this is just for the sake of demonstration, not a real DSN
16
// notice that only the injected config is used here, so there is
17
// a real separation of concerns here
18 19
return sprintf
(
20
'%s:%s@%s:%d'
,
21
$this
->
configuration
->
getUsername
(),
22
$this
->
configuration
->
getPassword
(),
23
$this
->
configuration
->
getHost
(),
24
$this
->
configuration
->
getPort
()
25
);
26
}
27
}
Тест
Tests/DependencyInjectionTest.php
1
2 3
declare
(strict_types
=
1
);
4 5
namespace
DesignPatterns\Structural\DependencyInjection\Tests;
6 7
use
DesignPatterns\Structural\DependencyInjection\DatabaseConfiguration;
8
use
DesignPatterns\Structural\DependencyInjection\DatabaseConnection;
9
use
PHPUnit\Framework\TestCase;
10 11
class
DependencyInjectionTest extends
TestCase
12
{
13
public function testDependencyInjection
()
14
{
15
$config
=
new
DatabaseConfiguration(
'localhost'
,
3306
,
'domnikl'
,
'1234'
);
16
$connection
=
new
DatabaseConnection(
$config
);
17 18
$this
->
assertSame
(
'domnikl:1234@localhost:3306'
,
$connection
->
getDsn
());
19
}
20
}
1.2. Структурные шаблоны проектирования (Structural)
57

DesignPatternsPHP Documentation, Выпуск 1.0 1.2.7 Фасад (Facade)
Назначение
The primary goal of a Facade Pattern is not to avoid you having to read the manual of a complex API. It’s only a side-effect. The first goal is to reduce coupling and follow the Law of Demeter.
Фасад предназначен для разделения клиента и подсистемы путем внедрения многих (но иногда только одного) интерфейсов, и, конечно, уменьшения общей сложности.
• Фасад не запрещает прямой доступ к подсистеме. Просто он делает его проще и понятнее.
• Вы можете (и вам стоило бы) иметь несколько фасадов для одной подсистемы.
Вот почему хороший фасад не содержит созданий экземпляров классов (new) внутри. Если внутри фасада создаются объекты для реализации каждого метода, это не Фасад, это Строитель или [Аб- страктная|Статическая|Простая] Фабрика [или Фабричный Метод].
Лучший фасад не содержит new или конструктора с type-hinted параметрами. Если вам необходимо создавать новые экземпляры классов, в таком случае лучше использовать Фабрику в качестве аргу- мента.
58
Глава 1. Паттерны

DesignPatternsPHP Documentation, Выпуск 1.0
Диаграмма UML
1   2   3   4   5   6   7   8   9


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