Вопрос шаблона проектирования: инкапсуляция или наследование - PullRequest
2 голосов
/ 07 мая 2010

У меня есть вопрос, который я долго трудился.Я создаю шаблонизатор с двумя основными классами Template.php и Tag.php, с кучей классов расширения, таких как Img.php и String.php.

Программа работает так:

Объект Template создает объекты Tag.Каждый объект тега определяет, какой класс расширения (img, string и т. Д.) Реализовать.

Смысл класса тега заключается в предоставлении вспомогательных функций для каждого класса расширения, таких как wrap('div'),addClass('slideshow') и т. Д.

Каждый класс Img или String используется для визуализации кода, соответствующего тому, что требуется, поэтому $Img->render() даст что-то вроде <img src='blah.jpg' />

Мой вопрос:

Должен ли я инкапсулировать все функциональные возможности расширения в объекте Tag следующим образом:

Tag.php

function __construct($namespace, $args) {
    // Sort out namespace to determine which extension to call
    $this->extension = new $namespace($this); // Pass in Tag object so it can be used within extension

    return $this; // Tag object
}

function render() {
    return $this->extension->render();
}

Img.php

    function __construct(Tag $T) {
        $args = $T->getArgs();
        $T->addClass('img');
    }

    function render() {
        return '<img src="blah.jpg" />';
    }

Использование:

$T = new Tag("img", array(...);
$T->render();

.... или я должен создать больше структуры наследования , потому что «Img is a Tag»

Tag.php

public static create($namespace, $args) {
    // Sort out namespace to determine which extension to call
    return new $namespace($args);

}

Img.php

class Img extends Tag {
    function __construct($args) {
        // Determine namespace then call create tag
        $T = parent::__construct($namespace, $args);
    }

    function render() {
        return '<img src="blah.jpg" />';
    }
}

Использование:

$Img = Tag::create('img', array(...));
$Img->render();

Одна вещь, которая мне нужна, это общий интерфейс для создания пользовательских тегов,то есть я могу создать экземпляр Img (...), а затем создать экземпляр String (...), янужно создавать экземпляры каждого расширения с помощью Tag.

EDIT: Также просто для пояснения: у класса Tag есть функциональные возможности, общие для всех классов расширений, в классе Tag не должно быть никаких методовэто должно быть реализовано в классах расширения.Класс тегов просто предоставляет вспомогательные функции.

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

Спасибо!Мэтт Мюллер

Ответы [ 2 ]

2 голосов
/ 07 мая 2010

Наследование будет иметь больше смысла, чем инкапсуляция всей функциональности для различных тегов в одном классе Tag. Разделение интересов важно, поэтому лучше использовать подход, основанный на наследовании. В противном случае у вас будет куча различной логики, специфичной для тегов, внутри одного класса, что плохо. Это кошмар обслуживания!

Если у вас есть Img -специфическая логика, поместите ее в свой класс. Вы можете поместить все общие методы в класс Tag. Если бы это была Java, я бы сделал Tag абстрактный класс или даже интерфейс и имел бы различные реализации (Img, Div и т. Д.), Расширяющие (в случае абстрактного класса) или реализующие (в случай интерфейса).

Еще лучшим подходом было бы иметь интерфейс Tag, а затем абстрактный класс AbstractTag, который реализует всю общую логику. Тогда ваши конкретные теги могут реализовать интерфейс Tag и расширить AbstractTag. Однако я не знаю, возможно ли это в PHP, но вы можете попробовать сделать что-то подобное.

1 голос
/ 07 мая 2010

Ни new Tag('img'), ни Tag::create('img') не выглядят убедительно для меня. Я думаю, решение о том, какой тег использовать, принимается не в том месте - в классе Tag - хотя он явно принадлежит шаблону. Тег и его потомки не должны иметь никакого контроля над тем, как они будут использоваться.

Я бы предложил следующее: создать иерархию тегов

 abstract class Tag { ...common methods.... }
 class ImgTag extends Tag { ...image specific methods... }
 class SpanTag extends Tag { ...image specific methods... }

, а в шаблоне просто используйте новый Wh whatTag, когда вам это нужно

 class Template...
    function insertImage
      $tag = new ImgTag($atts);
      $tag->render();

Если теги создаются в нескольких местах, желательно иметь фабричный метод, но он все равно должен принадлежать шаблону

 class Template...
    function createImage
      return new ImgTag($atts);

    function insertOneImage
      $tag = $this->createImage
      $tag->render();

    function insertAnotherImage
      $tag = $this->createImage
      $tag->render();

В качестве общего совета избегайте статических методов любой ценой. Статики - это просто причудливые псевдонимы для глобальных функций, в них нет ничего объектно-ориентированного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...