Шаблоны проектирования: Bridge
Долго думал о каком бы шаблоне написать, в результате решил остановиться на Bridge, шаблон, который практически никогда не встречал в мануалах по веб-разработке.
Итак, сформулируем проблему: При использовании наследования реализующий код жестко привязан к абстракции, что сильно усложняет независимую модификацию. Необходимо отделить абстракцию от реализации так, чтобы и то и другое можно было изменять независимо.
Допустим у нас есть задача создания списка статей разного типа, при этом также следует учесть, что формат вывода может иметь несколько вариаций.
Пример реализации:
<?php
abstract class Articles
{
protected $_viewType;
abstract function printAll();
function __construct($viewType)
{
$this->_viewType = $viewType;
}
protected function printLogic(array $articles)
{
if($this->_viewType == 'block')
{
$this->blockPrintLogic($articles);
}
else
{
$this->listPrintLogic($articles);
}
}
protected function blockPrintLogic(array $articles)
{
echo 'Вывод блоками: | '.
implode(' | ',$articles)
.' |';
}
protected function listPrintLogic(array $articles)
{
echo 'Вывод списком <br><ul><li>'.
implode('</li><li>',$articles)
.'</li></ul>';
}
}
class GameArticles extends Articles
{
function printAll()
{
$articles = array
(
'Статья об игре 1',
'Статья об игре 2',
'Статья об игре 3',
);
$this->printLogic($articles);
}
}
class VideoArticles extends Articles
{
function printAll()
{
$articles = array
(
'Статья о фильме 1',
'Статья о фильме 2',
'Статья о фильме 3',
);
$this->printLogic($articles);
}
}
$listGameArticles = new GameArticles('list');
$listGameArticles->printAll();
$blockVideoArticles = new VideoArticles('block');
$blockVideoArticles->printAll();
?>
В результате выполнения получим:
- Статья об игре 1
- Статья об игре 2
- Статья об игре 3
Вывод блоками: | Статья о фильме 1 | Статья о фильме 2
| Статья о фильме 3 |
Какие неудобства мы здесь видим? Код абстракции и код реализации связаны друг с другом, мы не можем проводить независимые модификации, хоть для одного разработчика это может и не быть проблемой, для группы программистов это несет негативные последствия.
Путем применения шаблона «Мост» мы не только избавляемся от проблем с модификациями в будущем, но и делаем структуру класса более изящной и логичной.
Вот как выглядит оптимизированный вариант:
<?php
abstract class Articles
{
protected $_articleView;
abstract function printAll();
function __construct(ArticleView $articleView)
{
$this->_articleView = $articleView;
}
protected function printLogic(array $articles)
{
$this->_articleView->printLogic($articles);
}
}
class GameArticles extends Articles
{
function printAll()
{
$articles = array
(
'Статья об игре 1',
'Статья об игре 2',
'Статья об игре 3',
);
$this->printLogic($articles);
}
}
class VideoArticles extends Articles
{
function printAll()
{
$articles = array
(
'Статья о фильме 1',
'Статья о фильме 2',
'Статья о фильме 3',
);
$this->printLogic($articles);
}
}
interface ArticleView
{
function printLogic(array $articles);
}
class BlockArticleView implements ArticleView
{
function printLogic(array $articles)
{
echo 'Вывод блоками: | '.
implode(' | ',$articles)
.' |';
}
}
class ListArticleView implements ArticleView
{
function printLogic(array $articles)
{
echo 'Вывод списком <br><ul><li>'.
implode('</li><li>',$articles)
.'</li></ul>';
}
}
$listGameArticles = new GameArticles(new ListArticleView());
$listGameArticles->printAll();
$blockVideoArticles =
new VideoArticles(new BlockArticleView());
$blockVideoArticles->printAll();
?>
Реализацию логики отображения мы вынесли в отдельный класс ArticleView, оставив в абстракции только необходимое.
Обратите также внимание на изменения в клиентском коде, код стал более строгим, уточнение типов не даст нам совершить ошибку при создании экземпляра статей.
Для более глубокого восприятия рекомендую отличную статью.
