Позднее связывание приводит к одному интересному следствию. Из базового класса можно вызывать методы и свойства, определённые в наследниках. Причём самих наследников может даже не существовать. Позднее связывание на то и позднее, что проверка происходит только в тот момент, когда этот код используется.
Эту особенность используют в паттерне "шаблонный метод". Он применяется тогда, когда у подклассов есть общая логика, которая частично опирается на поведение подклассов. Такая логика реализуется в методе базового класса, а та часть которая различается (для каждого подкласса), делегируется наследникам.
Возьмём для примера наши теги. Посмотрите на метод __toString()
. Видно, что его код, останется идентичным для большинства тегов. Единственное, что меняется – название самого тега.
<?php
class HTMLAnchorElement extends HTMLElement
{
public function __toString()
{
// Родительский метод
$attrLine = $this->stringifyAttributes();
// Родительский метод
$body = $this->getTextContent();
return "<a{$attrLine}>{$body}</a>";
}
}
Мы можем модифицировать код так, что метод __toString()
переместится в HTMLElement
. И единственная вещь, которая останется за подклассами – имя тега:
<?php
class HTMLElement
{
public function __toString()
{
$attrLine = $this->stringifyAttributes();
$body = $this->getTextContent();
// getTagName – метод, который должны реализовать все подклассы
$tagName = $this->getTagName();
return "<{$tagName}{$attrLine}>{$body}</{$tagName}>";
}
}
Получившийся код лучше исходного варианта, так как он значительно сокращает дублирование (тегов около 100 штук!). Но есть одна загвоздка. Теги бывают одиночные, а значит текущий вариант __toString
не подойдёт для них. Из этой ситуации можно выйти разными способами, например, с помощью наследования.
Создадим у HTMLElement два подкласса: один HTMLSingleElement и HTMLPairElement. Теперь классы конкретных тегов должны наследоваться от одного из указанных классов. В каждом из этих классов будет своя реализация метода __toString()
.
<?php
class HTMLSingleElement extends HTMLElement
{
public function __toString()
{
$attrLine = $this->stringifyAttributes();
// getTagName – метод, который должны реализовать все подклассы
$tagName = $this->getTagName(); // <== метод, который должны реализовывать наследники
// Создаётся одиночный тег
return "<{$tagName}{$attrLine}>"
}
}
class HTMLPairElement extends HTMLElement
{
public function __toString()
{
$attrLine = $this->stringifyAttributes();
$body = $this->getTextContent();
// getTagName – метод, который должны реализовать все подклассы
$tagName = $this->getTagName(); // <== метод, который должны реализовывать наследники
return "<{$tagName}{$attrLine}>{$body}</{$tagName}>";
}
}
Несмотря на различия в реализации __toString()
, оба этих подкласса требуют от своих наследников реализации одного и того же метода getTagName()
.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.