Скорая Компьютерная Помощь г. Калуга

Полный спектр компьютерных услуг!

Здравствуйте, гость ( Вход | Регистрация )

> Внимание!

  • Вся информация, расположенная в данном и других разделах форума получена из открытых источников (интернет-ресурсы, средства массовой информации, печатные издания и т.п.) и/или добавлена самими пользователями. Администрация форума предоставляет его участникам площадку для общения / размещения файлов / статей и т.п. и не несет ответственности за содержание сообщений, а также за возможное нарушение авторских, смежных и каких-либо иных прав, которое может повлечь за собой информация, содержащаяся в сообщениях.
Ремонт компьютеров в калуге Рекламное место сдается
 
Ответить в эту темуОткрыть новую тему
> [Из песочницы] PHP и Temporal Coupling
Decker
сообщение 11.4.2016, 13:09
Сообщение #1


Администратор
*****

Группа: Главные администраторы
Сообщений: 14349
Регистрация: 12.10.2007
Из: Twilight Zone
Пользователь №: 1




Разработка*,
Алгоритмы*,
PHP*
Про архитектуру приложений на PHP было написано не один десяток статей, но на данной проблеме больше акцентируют внимание разработчики Java и C#. Суть ее заключается в жесткой зависимости одного свойства на другом.



Представим следующую ситуацию:



Использование сеттера<?php

class Page
{
/**
* @var string
*/
private $content;

/**
* @param $content
*/
public function setContent($content)
{
$this->content = $content;
}
}

class PageBuilder
{
/**
* @var Page
*/
private $page;

/**
* @param $page
*/
public function setPage($page)
{
$this->page = $page;
}

/**
* @param $content
* @return $this
*/
public function setContent($content)
{
$this->page->setContent($content);

return $this;
}

/**
* @return Page
*/
public function build()
{
return $this->page;
}
}




$pageBuilder = new PageBuilder();
$pageBuilder->setPage(new Page());
$pageBuilder->setContent('Test content');
$pageBuilder->build();


В данном примере видно, что $pageBuilder->build() является потенциально опасным и может привести к фатальной ошибке если $pageBuilder->setPage(new Page()) не был предварительно вызван. Другая часто встречающаяся ошибка — использование методов init() или initialization():



Использование инициализатораclass Page
{
// Class
}

class PageBuilder
{
/**
* @var Page
*/
private $page;

/**
* Initialization
*/
public function init()
{
$this->page = new Page();
}

/**
* @param $content
* @return $this
*/
public function setContent($content)
{
$this->page->setContent($content);

return $this;
}

/**
* @return Page
*/
public function build()
{
return $this->page;
}
}




$pageBuilder = new PageBuilder();
$pageBuilder->init();
$pageBuilder->setContent('Test content');
$pageBuilder->build();


Если мы забудем вызвать метод init(), нас также ждут неприятности. Данный код является отличным примером плохой архитектуры приложения. Методы-инициализаторы пытаются вести себя как конструкторы, которыми не являются по определению.



Для избежания Temporal Coupling нужно всегда пользоваться правилами:



  • экземпляр класса должен быть готов для использования сразу же после создания;
  • конструкторы не должны выполнять никакой логики кроме инициализации свойств класса;



Инъекция зависимости через конструктор


Это решение является оптимальным и предпочтительным в большинстве случаев. Мы можем использовать механизмы Dependency Injection из Symfony, Laravel или других современных фреймворков.



Инъекция через конструкторclass Page
{
// Class
}

class PageBuilder
{
/**
* @var Page
*/
private $page;

/**
* PageBuilder constructor.
* @param Page $page
*/
public function __construct(Page $page)
{
$this->page = $page;
}

// Методы-сеттеры
}

$pageBuilder = new PageBuilder();
$pageBuilder->setContent('Test content');
$pageBuilder->build();





Абстрактная фабрика


Немного модифицируем наш код, добавив абстрактную фабрику:



Абстрактная фабрика<?php

class Page
{
// Class
}

class PageBuilder
{
/**
* @var Page
*/
private $page;

/**
* PageBuilder constructor.
* @param Page $page
*/
public function __construct(Page $page)
{
$this->page = $page;
}

/**
* @param $content
* @return $this
*/
public function setContent($content)
{
$this->page->setContent($content);

return $this;
}

/**
* @return Page
*/
public function build()
{
return $this->page;
}
}

class PageBuilderFactory implements FactoryInterface
{
/**
* @param Page|null $page
* @return PageBuilder
*/
public function create(Page $page = null)
{
if (null === $page) {
$page = new Page();
}

return new PageBuilder($page);
}
}

$pageBuilderFactory = new PageBuilderFactory();
$pageBuilder = $pageBuilderFactory->create();
$pageBuilder->setContent('Test content');
$pageBuilder->build();




Как видим, экземпляр класса Page создан без явного вызова и будет доступен нашему билдеру.




Заключение


Temporal Coupling нужно всегда избегать, вне зависимости от сложности приложения, влияния code-review или других факторов. Также помните что конструкторы должны выполнять только логику, связанную с инъекциями. Иначе вы рискуете получить ухудшение быстродействия на этапе создания экземпляров класса.




Полезные ссылки




Original source: habrahabr.ru (comments, light).

Читать дальше


--------------------

Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

Рекламное место сдается Рекламное место сдается
Текстовая версия Сейчас: 29.1.2025, 23:40
Рейтинг@Mail.ru
Яндекс.Метрика Яндекс цитирования