Звоните супер
Эта статья в значительной степени или полностью опирается на один источник . ( август 2010 г. ) |
Вызов super — это запах кода или антишаблон некоторых объектно-ориентированных языков программирования. Вызов супер — это шаблон проектирования, в котором конкретный класс предусматривает, что в производном подклассе пользователь должен переопределить метод и вызвать саму переопределенную функцию в определенной точке. Переопределенный метод может быть намеренно неполным и зависеть от переопределяющего метода для расширения его функциональности в установленном порядке. Однако тот факт, что сам язык не может обеспечить соблюдение всех условий, предписанных для этого вызова, делает это антишаблоном.
Описание
[ редактировать ]В объектно-ориентированном программировании пользователи могут наследовать свойства и поведение суперкласса в подклассах. Подкласс может переопределять методы своего суперкласса, заменяя реализацию метода суперкласса собственной реализацией. Иногда переопределяющий метод полностью заменяет соответствующую функциональность в суперклассе, тогда как в других случаях метод суперкласса все равно необходимо вызывать из переопределяющего метода. Поэтому большинство языков программирования требуют, чтобы переопределяющий метод явно вызывал переопределенный метод суперкласса для его выполнения.
Суперанти-шаблон вызова полагается на то, что пользователи интерфейса или платформы получают подкласс от определенного класса, переопределяют определенный метод и требуют, чтобы переопределенный метод вызывал исходный метод из переопределяющего метода: [1]
Это часто требуется, поскольку суперкласс должен выполнить некоторые задачи по настройке, чтобы класс или платформа работали правильно, или поскольку основная задача суперкласса (которая выполняется этим методом) только дополняется подклассом.
Антишаблон — это требование вызова родителя. В реальном коде есть много примеров, когда методу подкласса все еще может потребоваться функциональность суперкласса, обычно там, где он только дополняет функциональность родительского класса. Если ему все равно приходится вызывать родительский класс, даже если он полностью заменяет функциональность, антишаблон присутствует.
Лучший подход к решению этих проблем — вместо этого использовать шаблон метода шаблона , где суперкласс включает чисто абстрактный метод, который должен быть реализован подклассами, и исходный метод вызывает этот метод: [1]
Языковые вариации
[ редактировать ]Появление этого антишаблона в программах обычно связано с тем, что немногие языки программирования предоставляют возможность по контракту гарантировать вызов суперметода из производного класса. Одним из языков, который имеет эту функцию, причем весьма радикальным образом, является BETA . Эта функция ограниченно встречается, например, в Java и C++ , где конструктор дочернего класса всегда вызывает конструктор родительского класса.
Языки, поддерживающие методы до и после , такие как Common Lisp (в частности, Common Lisp Object System ), предоставляют другой способ избежать этого антишаблона. Программист подкласса может вместо переопределения метода суперкласса предоставить дополнительный метод, который будет выполняться до или после метода суперкласса. Кроме того, программист суперкласса может указать методы before , after иaround , которые гарантированно будут выполнены в дополнение к действиям подкласса.
Пример
[ редактировать ]Предположим, есть класс для формирования отчета об инвентаризации магазина видеопроката. В каждом конкретном магазине есть свой способ табулирования доступных на данный момент видео, но алгоритм формирования итогового отчета одинаков для всех магазинов. Платформа, использующая суперанти-шаблон вызова, может предоставить следующий абстрактный класс (в C# ):
abstract class ReportGenerator
{
public virtual Report CreateReport()
{
// Generate the general report object
// ...
return new Report(...);
}
}
Ожидается, что пользователь класса реализует подкласс следующим образом:
class ConcreteReportGenerator : ReportGenerator
{
public override Report CreateReport()
{
// Tabulate data in the store-specific way
// ...
// Design of this class requires the parent CreateReport() function to be called at the
// end of the overridden function. But note this line could easily be left out, or the
// returned report could be further modified after the call, violating the class design
// and possibly also the company-wide report format.
return base.CreateReport();
}
}
Предпочтительный интерфейс выглядит так:
abstract class ReportGenerator
{
public Report CreateReport()
{
Tabulate();
// Generate the general report object
// ...
return new Report(...);
}
protected abstract void Tabulate();
}
Реализация переопределит этот класс следующим образом:
class ConcreteReportGenerator : ReportGenerator
{
protected override void Tabulate()
{
// Tabulate data in the store-specific way
// ...
}
}