Comments 9
Хочу продолжение!
Фишка АОП же вроде в том что там компилятор сам генерирует обертки. А здесь нужно все руками делать - создавать функциональный объект и явно его везде вызывать вместо исходной функции.
Пожалуйста, не пишите так на Go. Оставьте эту дрянь для джавы. Решайте реальные задачи вместо построения сферических коней в вакууме — и обнаружите, что они прекрасно решаются простыми средствами. Например, через замыкание.
var nCalls = 0
func count(fn func()) {
fn()
nCalls++
}
func main() {
sum := func(a int, b int) int {
return a + b
}
total := 0
count(func() { total += sum(1, 2) })
count(func() { total += sum(3, 4) })
count(func() { total += sum(5, 6) })
fmt.Println(total)
// 21
fmt.Println(nCalls)
// 3
}
По сравнению с приведенным в статье примером, конечно, Ваше решение быстрее. Однако, вам приходится использовать замыкание, чтобы каждый раз пробрасывать в count
и аргументы функции sum, и переменную для сохранения результата. В моем же примере я использую запроксированную функцию так, как будто для нее ничего не изменилось. А еще обертка знает и аргументы вызванной функции, и ее результат, и может, например, выводить их в консоль. Или, допустим, проверять, вернула ли исходная функция ошибку. И если да, то попробовать выполнить ее еще несколько раз, пока она не вернет результат. При разумном использовании это может быть довольно интересным инструментом.
Но, как я и отмечал в конце статьи, использование рефлексии сильно замедляет код. И да, не очень-то типично для Go, ратующего за прозрачность. Отсюда и название "... и почему вам не стоит этого делать" )))
Откуда эта страсть к переусложнению на ровном месте?
Если уж делать AOP в го, то логичней использовать кодогенерацию через AST пакет. Но лучше AOP не делать вообще и дело вовсе не в производительности(для большинства приложений лишние 200 наносекунд на вызове функции абсолютно незаметны). Дело в том, что в го, как в языке, есть концепция - код должен быть простым, однозначным и очевидным. Должен быть только один путь сделать что-то. Именно по этому в го нет такого количества синтаксического сахара, как в других языках и сами программы выглядят более многословными, но хорошо читабельными. Да, вы можете пытаться использовать в го AOP, DI, ORM и т.д., эмулировать ООП, делать политики создания абстрактных фабрик, но делать это будет неудобно и выглядеть оно будет неогранично. Мое субъективное мнение, что го отлично подходит для рапид-девелопмента, когда вам надо быстро сделать какой-то тул или создать еще один микросервис, которые будет небольшим и сосредоточеным на одной конкретной задаче. В этом случае вам никакие AOP просто не нужны, вы всю нужную логику напишите быстрее, чем будете гуглить документацию и писать обязательный бойлерплейт. А если вам надо делать огромный монореп, с миллионами строк кода, кучей объектов предметной области в одном приложении-сервисе, с множеством правил их взаимодействия, исключений из правил, самой разной бизнес логики, над которым одновременно работают десятки программистов и все это не возможно поддерживать без множества слоев абстраций, то лучше просто не использовать го, а посмотреть в сторону других языков - той же джавы, котлина, сишарпа.
Не надо так... Пожалуйста, оставайтесь на java и не пишите код на go. Зачем забивать гвозди микроскопом? Потом обычным гошникам очень тяжело будет после вас поддерживать проект, проще будет выкинуть всё и переписать.
AOP в Golang: как рефлексировать, и почему вам не стоит этого делать