Звоните супер - Call super

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

Описание

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

Супер анти-шаблон вызова полагается на то, что пользователи интерфейса или фреймворка производят подкласс из определенного класса, переопределяют определенный метод и требуют, чтобы переопределенный метод вызвал исходный метод из метода переопределения:[1]

Антипаттерн CallSuper

Это часто требуется, поскольку суперкласс должен выполнять некоторые задачи по настройке для правильной работы класса или инфраструктуры, или поскольку основная задача суперкласса (которая выполняется этим методом) только дополняется подклассом.

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

Лучшим подходом к решению этих проблем является использование шаблон метода шаблон, где суперкласс включает чисто абстрактный метод, который должен быть реализован подклассами и иметь исходный метод, вызывающий этот метод:[1]

Как избежать анти-паттерна CallSuper

Вариант языка

Появление этого антишаблона в программах обычно происходит из-за того, что немногие языки программирования предоставляют возможность по контракту гарантировать, что супер-метод вызывается из производного класса. Одним из языков, который действительно имеет эту функцию в довольно радикальной манере, является БЕТА. Эта функция ограничена, например, в Ява и C ++, где конструктор дочернего класса всегда вызывает конструктор родительского класса.

Языки, поддерживающие перед и после методы, такие как Common Lisp (в частности Общая объектная система Lisp ), предоставьте другой способ избежать этого антипаттерна. Программист подкласса может вместо переопределения метода суперкласса предоставить дополнительный метод, который будет выполняться до или после метода суперкласса. Также программист суперкласса может указать перед, после, и вокруг методы, которые гарантированно будут выполняться в дополнение к действиям подкласса.

Пример

Предположим, есть класс для создания отчета об инвентаризации магазина видеопроката. В каждом конкретном магазине есть свой способ табулирования видео, доступных в настоящее время, но алгоритм генерации окончательного отчета одинаков для всех магазинов. Фреймворк, использующий суперантипаттерн вызова, может предоставлять следующий абстрактный класс (в C # ):

Абстрактные учебный класс ReportGenerator {    общественный виртуальный Отчет CreateReport() {        // Генерация общего объекта отчета        // ...        возвращаться новый Отчет(...);    }}

Ожидается, что пользователь класса реализует подкласс следующим образом:

учебный класс ConcreteReportGenerator : ReportGenerator {    общественный отменять Отчет CreateReport() {        // Табулирование данных в зависимости от магазина        // ...        // Дизайн этого класса требует, чтобы родительская функция CreateReport () вызывалась в         // конец замещенной функции. Но обратите внимание, что эту строку можно легко пропустить, или        // возвращенный отчет может быть изменен после вызова, нарушая дизайн класса        // и, возможно, формат отчета в масштабах компании.        возвращаться основание.CreateReport();    }}

Предпочтительный интерфейс выглядит так:

Абстрактные учебный класс ReportGenerator {    общественный Отчет CreateReport() {        Табулировать();        // Генерация общего объекта отчета        // ...        возвращаться новый Отчет(...);    }     защищенный Абстрактные пустота Табулировать();}

Реализация переопределит этот класс следующим образом:

учебный класс ConcreteReportGenerator : ReportGenerator {    защищенный отменять пустота Табулировать() {        // Табулирование данных в зависимости от магазина        // ...    }}

Рекомендации

  1. ^ а б Фаулер, Мартин. «МФ Блики: CallSuper».