Шаблоны проектирования: 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, оставив в абстракции только необходимое.

Обратите также внимание на изменения в клиентском коде, код стал более строгим, уточнение типов не даст нам совершить ошибку при создании экземпляра статей.

Для более глубокого восприятия рекомендую отличную статью.



Теги: ,

Оставить комментарий

Premium Wordpress Themes