Как вы решаете между использованием декораторов и наследованием, когда возможны оба варианта?
Например, эта проблема имеет два решения.
Меня особенно интересует Python.
Как вы решаете между использованием декораторов и наследованием, когда возможны оба варианта?
Например, эта проблема имеет два решения.
Меня особенно интересует Python.
Декораторы...
например.
@decoA
@decoB
@decoC
def myFunc(...): ...
...
Является эквивалентным:
def myFunc(...): ...
...
myFunc = decoA(decoB(decoC(myFunc))) #note the *ordering*
Множественное наследование...:
__init__
не будет вызываться, если он явно не указан (через протокол метода-разрешения-заказа)!Подводя итог, я бы использовал декораторы для смешанного поведения, если они не возвращали прокси-объекты. Некоторые примеры включают в себя любой декоратор, который возвращает исходную функцию, слегка измененную (или после регистрации ее где-то или добавления ее в какую-то коллекцию).
Вещи, которые вы часто найдете декораторами для (например, memoization), также являются хорошими кандидатами, но их следует использовать в модерации, если они возвращают объекты-прокси; порядок, в котором они применяются, имеет значение. И слишком много декораторов друг над другом используют их так, как они не предназначены для использования.
Я бы подумал об использовании наследования, если это была "классическая проблема наследования", или если все, что мне нужно для поведения mixin, были методами. Классическая проблема наследования - это та, где вы можете использовать ребенка везде, где вы могли бы использовать родителя.
В общем, я пытаюсь написать код, где нет необходимости улучшать произвольные вещи.
Проблема, о которой вы говорите, не решает между декораторами и классами. Это с помощью декораторов, но у вас есть возможность использовать либо:
Декоратор - просто причудливое имя для шаблона "обертка", то есть замена чего-то другим. Реализация зависит от вас (класс или функция).
При решении между ними это полностью зависит от личных предпочтений. Вы можете делать все, что вы можете сделать в одном с другим.
(Почему это хорошая идея? Могут быть предположения, что украшенная функция все еще является функцией, а украшенный класс по-прежнему является классом.)
Еще лучше в обоих случаях было бы использовать декоратор, который просто возвращает оригинал, каким-то образом измененный.
изменить: После лучшего понимания вашего вопроса я опубликовал другое решение в Python functools.wraps эквивалентно для классов
Если оба эквивалентны, я бы предпочел декораторы, так как вы можете использовать один и тот же декоратор для многих классов, тогда как наследование применяется только к одному конкретному классу.
Лично я бы подумал о повторном использовании кода. Декоратор иногда более гибкий, чем наследование.
В качестве примера возьмем кэширование. Если вы хотите добавить средство кэширования к двум классам в вашей системе: A и B, с наследованием, вы, вероятно, закончите работу с ACached и BCached. И, переопределив некоторые из методов в этих классах, вы, вероятно, дублируете много кодов для одной и той же логики кэширования. Но если вы используете декоратор в этом случае, вам нужно только определить один декоратор, чтобы украсить оба класса.
Итак, когда вы решаете, какой из них использовать, вы можете сначала проверить, является ли расширенная функциональность только конкретной для этого класса или если одна и та же расширенная функциональность может быть повторно использована в других частях вашей системы. Если его нельзя использовать повторно, то наследование должно, вероятно, выполнять эту работу. В противном случае вы можете подумать об использовании декоратора.