Дополнительные материалы интервью по Java (операционная система, сеть, zk, mq, redis, java и т. д.):GitHub.com/ с Ха Цяном 12…
Вывод первыйДля функций, которые могут быть достигнуты с помощью аннотаций Java, компетентны большинство декораторов Python.Декоратор больше похож на комбинацию аннотаций и Aop в Java.
Python — это минималистский язык, язык простой и легкий в освоении, но все еще есть некоторые продвинутые методы, такие как декораторы, сопрограммы и параллелизм, которые могут заставить людей чувствовать себя сбитыми с толку, разочарованными и разочарованными.Эта статья будет посвящена декораторам Python. Использование общих примеров позволяет нам более интуитивно увидеть мощную выразительную силу декораторов и, наконец, дает общие инструменты для написания декораторов.
Учащиеся, знакомые с Java, должны быть знакомы с использованием аннотаций. С помощью аннотаций можно определить конфигурацию метаданных. У нас часто возникает такое чувство: "Пока эта аннотация добавлена, мой компонент будет зарегистрирован", " Пока эта аннотация добавлена, она добавит управление транзакциями», а также смущает: «Почему эта аннотация до сих пор не действует?», python не предоставляет аннотаций, подобных Java, но предоставляет декораторы, которые более мощные, чем аннотации. Например, маршрут, обработчик ошибок в веб-фреймворке Flask и собственное свойство python, статический метод и т. д. На самом деле, большинство функций, которые могут быть достигнуты с помощью аннотаций java, декораторы Python являются компетентными, а декораторы больше похожи на комбинацию аннотаций и Aop в Java, На этом выводе мы сосредоточимся в конце. Теперь давайте сначала объясним использование декораторов на простом примере печати журнала.
Простой пример декоратора 1.0
def log(func): #@1
def func_dec(*args, **kwargs): #@2
r = func(*args, **kwargs) #@3
print("didiyun execute done:%s" % func.__name__)
return r
return func_dec
@log #@4
def test_dec(size, length, ky=None):
print "didiyun execute test_dec param:%s, %s, %s" % (size, length, ky)
def test():
test_dec(ky="yuhaiqiang", length=3, size=1)
""
输出结果可以看到装饰器的装饰逻辑已正确被执行
didiyun execute test_dec param:1, 3, yuhaiqiang
didiyun execute done:test_dec
""
@1 定义 log 装饰器,输入参数func是需要被装饰的函数,本例中输出打印是 test_dec
@2 定义一个装饰函数,参数类型包括变长的位置参数和名字参数,适应被装饰函数不同的参数组合,这种写法可以代表任意参数组合
@3 执行实际的函数func_dec, 注意处理返回值,不要"吞掉"被装饰函数的返回值
@4 在被装饰函数上添加装饰器,注意此处不要加(),后面会解释具体原因,了解该原因,就能完全了解装饰器的小九九
Декоратор может добавлять дополнительные функции к внешнему слою функции, чтобы украсить исходную функцию. В этом примере декоратор просто печатает строку логов вне функции, которая реализует очень простую функцию. На самом деле декоратор не «просто небольшой трюк для печати журналов», но и для достижения других более полезных функций
2. Используйте декораторы для блокировки файлов
2.1 Использование fcntl для блокировки файлов
class Lock:
def __init__(self, filename, block=True):
#block 参数为 true代表阻塞式获取。 False为非阻塞,如果获取不到立刻返回 false
self.filename = filename
self.block = block
self.handle = open(filename, 'w')
def acquire(self):
if not self.block:
try:
fcntl.flock(self.handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
return True
except:
return False
else:
fcntl.flock(self.handle, fcntl.LOCK_EX)
return True
def release(self):
fcntl.flock(self.handle, fcntl.LOCK_UN)
self.handle.close()
С помощью библиотеки fcntl мы реализовали блокировки файлов.Заинтересованные читатели могут узнать больше о библиотеке fcntl.Давайте возьмем блокировки файлов в качестве примера, чтобы представить некоторые полезные и распространенные функции декораторов.
2.2 Определение декоратора блокировки файлов
def file_lock(lock_name, block=True): #@1
def wrapper(func):
def f(*args, **kwargs):
name = lock_name
lock = Lock(name, block)
acquire = lock.acquire()
if not acquire:
print("failed to acquire lock:%s,now ignore" % name)
return #@2
print("acquire process lock:%s" % name)
try:
return func(*args, **kwargs)
finally:
lock.release() #@3
print("release process lock:%s" % name)
return f
return wrapper
@file_lock(name="/var/local/file", block=True) #@4
def get_length():
pass
get_length()
输出 #@5
acquire process lock:/var/local/file
execute test_dec param:1
release process lock:/var/local/file
- Определите декоратор file_lock, принимая два параметра, lock_name: путь блокировки, block: блокирует ли получение
- В этот момент, когда получение блокировки не удается, возвращается только None, и вызывающий не может четко знать, является ли None возвращаемым значением get_length или получение блокировки завершается неудачно. Вызывающий объект восходящего потока обрабатывает исключение, связанное с ошибкой операции получения блокировки.
- try наконец гарантирует, что блокировку можно снять
- При использовании файловой блокировки также необходимо указать значение блокировки. Можете ли вы указать значение по умолчанию? Заблокирован только метод экземпляра, и читатель может подумать, как его реализовать. Кроме того, внимательные читатели могут сравнить, что декоратор file_lock добавляет круглые скобки (), но разница между ними заключается не только в том, что у одного есть параметры, а у другого нет параметров.В следующем разделе объясняется синтаксическая сахарная сущность декоратора.
- При фактическом использовании в проекте часто возникает проблема блокировки файла.На этапе отладки проекта, поскольку часто приходится вручную завершать программу принудительного уничтожения, блокировка файла не снимается должным образом.Читатели могут рассмотреть Укажите блокировку файла в фиксированном каталоге.Каждый раз при запуске процесса проверяйте, есть ли процесс с таким же путем.Если нет, то можете очистить каталог.Если есть процесс с таким же путем, значит, есть является параллельным выполнением, и каталог не очищается. Без очистки блокировка никогда не может быть получена. Если вы на самом деле не используете приведенный выше код для реализации блокировки файлов, вы можете Игнорируйте эту проблему, она не влияет на понимание декораторов. Заинтересованные читатели могут попробовать его, надеясь придумать лучшую схему блокировки файлов.
После использования блокировки файла вызов этого метода должен сначала получить блокировку, иначе он может сначала заблокировать. Таким образом, фактический метод обработки не должен иметь дело с логикой синхронизации, требуется только одна строка декоратора, а функция синхронизации дополнительно расширена.Благодаря контролю исключений он также может гарантировать, что блокировка файла может быть снята, чтобы избежать блокировки файла. утечка. Мы также можем добиться этого с помощью декоратора. много других полезных функций , но реализация декоратора блокировки файлов сложнее, чем декоратора журнала. Если вы внимательно посмотрите, он имеет три вложенных уровня функций. Мы оптимизируем эту проблему позже.
2.3 Объясните вопрос 1.0, когда для использования декораторов нужно добавить круглые скобки ()
В примере декоратора лога 1.0 мы оставили вопрос, почему декоратору лога не нужно добавлять(), а использование декоратора файловой блокировки добавляет()
Возвращаясь к реализации декоратора 1.0, если мы не будем использовать метод @log, что, если мы воспользуемся следующим методом?Можем ли мы реализовать ту же логику?
@log
def foo():
pass
foo() # 相当于 log(foo)(),log(func) 返回装饰函数,最后的括号代表执行
foo = log(foo) # 就是装饰器语法糖帮我们做的
Параметр, принимаемый методом журнала, это func.Естественно, когда вручную и явно вызывается функция оформления журнала foo, это никак не влияет на функцию оформления.Но кажется, что мы очень многословны и глупы.К счастью, python Предоставляет синтаксический сахар для декораторов, который можно использовать так, как если бы мы выполняли декорирование вручную. Но что значит, если мы добавим круглые скобки?Написание @log() эквивалентно вызову функции журнала без передачи ей параметров? Фактический интерпретатор Python «протестует» таким образом.
Но почему скобки добавляются к блокировке файла?Ответ заключается в том, что декоратору иногда нужны некоторые дополнительные параметры, такие как маршрут, который мы обычно используем во Flask, нам нужно указать Flask, как сопоставить URL с конкретным обработчиком, естественно, мы нужно указать маршрут, какой URL-адрес необходимо привязать, аналогично весеннему @RequestMapping
Когда декоратор добавляется с параметрами, я с удивлением обнаруживаю, что декоратор больше похож на трехслойную функцию..., разборчивость крайне плохая, но как только мы это поймем, мы обнаружим, что трехслойная функция причина
Можно было бы понимать так, когда у декоратора нет параметров, как у декоратора журнала, декоратор принимает параметр func, мы называем его "двухслойным" декоратором, его принцип мы разобрали выше, foo = log(foo). Знак @ декоратора эквивалентен указанию интерпретатору Python: «Вы передаете функцию @ следующей строки в качестве параметра декоратору, а затем присваиваете возвращаемое значение функции», что эквивалентно для выполнения foo = log(foo) Когда мы вызываем foo(), это эквивалентно вызову log(foo)().
Что касается декоратора file_lock(name, block) с параметрами, мы разбираемся в два этапа и рассматриваем трехуровневую реализацию функции file_lock. На втором уровне мы определяем функцию-оболочку, которая принимает параметр func, а затем мы в file_lock вернуть его в конце, мы можем думать, что
@file_lock(name="/var/local/test",block=True)
def test()
pass
wrapper = file_lock(name, block) #第一阶段
test = wrapper(test) #第二阶段
На первом этапе выполняется самая внешняя функция file_lock и возвращается оболочка. На втором этапе используем обертку для украшения теста Со вторым этапом мы уже знакомы. Фактически только первый этап является многократным. Поскольку мы добавили к нему дополнительную скобку, интерпретатор Python, естественно, выполнит функцию, которая вернет другую декорированную функцию и, следовательно, второй этап.
Интерпретатор Python хочет, чтобы мы понимали это именно так, иначе написание трехслойной функции будет очень утомительным. Позже мы продолжим исследовать, могут ли декораторы реализовать ту же функцию, но могут ли они избавиться от кошмара написания трехуровневых функций.
Вышеприведенное анализирует разницу между декораторами с параметрами и без них, а также то, как понимать и принимать это письмо в виду.Python использует синтаксический сахар и определения декораторов выше функций, чтобы заменить глупые ручные вызовы декорирования. Мы можем реализовать сложные декораторы, но предоставить чрезвычайно Обнадеживает использование элегантных способов обращения к вызывающим объектам, на самом деле фреймворк Python использует множество декораторов. Он также иллюстрирует силу и элегантность декораторов.
3. Время выполнения и последовательность методов декоратора Python
Python — это язык для интерпретации и выполнения. Давайте проведем небольшой эксперимент. В приведенном выше примере сначала определяется декоратор журнала, а затем используется декоратор журнала. Если вы замените порядок
@log("say some thing")
def test_dec(size, length, ky=None):
print "execute test_dec param:%s, %s, %s" % (size, length, ky)
def log(info=None):
def wrapper(func):
def func_dec(*args, **kwargs):
r = func(*args, **kwargs)
print("execute done:%s" % func.__name__)
return r
return func_dec
return wrapper
Нет сомнений, что это сообщит о синтаксической ошибке. Python выполняет интерпретацию и выполнение сверху вниз файла Python. Его можно использовать только в том случае, если журнал был определен. В python функции являются гражданами первого класса, а функции также являются объектами.Когда вы определяете функцию, вы объявляете объект функции.
def foo():
pass
def foo() объявляет объект функции, foo является ссылкой на объект функции, мы можем дополнительно определить свойства объекта и проверить свойства объекта функции через dir(foo), что на самом деле не то же самое, что объект экземпляра класса.
Как упоминалось выше, после того, как тест оформлен журналом, test() эквивалентен log(test)() , а декоратор python интерпретирует и выполняет @log def test(), что эквивалентно test=log(test). время объект функции, на который ссылается тест, является объектом функции, оформленным в журнале.
@log
def test():
pass
test=log(test)
3.2 Порядок выполнения декораторов
В реальной разработке мы часто сталкиваемся с использованием нескольких декораторов.Если читатели понимают концепцию объектов-функций в 3.0 и выше, они должны быть в состоянии угадать порядок оформления декораторов, который естественно выполняется сверху вниз. foo = a(b(c(foo))) но фактический порядок выполнения кода c->b->a
@a
@b
@c
def foo()
pass
Выше мы представили использование декораторов с помощью декораторов журналов и декораторов блокировок файлов, а также обсудили разницу между декораторами с параметрами и без них. Среди них метод определения "трехслойной функции" очень плохо читаем. В следующем разделе мы сосредоточимся на том, как использовать классы для реализации декораторов, упростить логику трехслойных декораторов и сократить написание подобные коды.
4. Дизайн класса декоратора
В этом разделе мы сосредоточимся на оптимизации написания трехслойного декоратора.Кроме того, автор также нашел другие общие требования в реальной разработке, Например
- Временно сохраните параметры декоратора. Ожидается, что параметры декоратора можно найти через декорированную функцию.Автор использует декоратор для определения тестового примера в автоматизированном тесте.Необходимо настроить информацию метаданных в случае и получить доступ к информации метаданных в фактическом исполнение двигатель часть. заключается в том, чтобы поместить информацию метаданных в объект функции
- Зарегистрируйте оформленный объект функции. Например, некоторые веб-фреймворки, обработчики регистрации, должны реализовать некоторую логику регистрации в декораторе.
Из вышеприведенных трех пунктов мы видим, что логика декоратора имеет некоторые общие части.Однако приведенные выше примеры декораторов все реализованы через функции, но функции явно уступают классам с точки зрения внутреннего состояния и наследования, поэтому мы попробуйте использовать Класс реализует декоратор. и попытайтесь реализовать общий декорированный базовый класс
4.1 Идеи
Python предоставляет множество сингулярных методов.Так называемый сингулярный метод означает, что пока вы реализуете этот метод, вы можете использовать некоторые инструментальные методы Python, такие как реализация метода __ len__, вы можете использовать len() для получения длины, и реализовать __ iter__ Вы можете использовать метод iter для возврата итератора, другие методы Также «__eq__», «__ne__», «__next__» и т. д. Среди них при реализации метода __call__ класс можно использовать как функцию, как в следующем примере
class FuncClass(object):
def __call__(self):
print("didiyun")
>>>F = FuncClass()
>>>F()
didiyun
Можно ли использовать эту функцию Python для реализации декораторов? Ответ положительный, давайте реализуем базовый класс для декорирования, чтобы решить вышеуказанные болевые точки.
class BaseDecorator(object):
def __call__(self, *_, **kwargs): #@1
return self.do_call(**kwargs) #@2
def do_call(self, *_, **decorator_kwargs):
def wrapper(func):
wrapper.__explained = False
@wraps(func) #@3
def _wrap(*args, **kwargs):
if not wrapper.__explained: #@4
self._add_dict(func, decorator_kwargs)
wrapper.__explained = True
return self.invoke(func, *args, **kwargs) #@5
self._add_dict(_wrap, decorator_kwargs)
_wrap = self.wrapper(_wrap) #@6
return _wrap
return wrapper
def wrapper(self, wrapper):
return wrapper
def _add_dict(self, func, decorator_kwargs):
for k, v in decorator_kwargs.items():
func.__dict__[k] = v
def invoke(self, func, *args, **kwargs):
return func(*args, **kwargs)
BaseDecorator实现的并不是具体的某个装饰器逻辑,它可以作为装饰器类的基类,以上我们曾分析编写装饰器通用的需求已经痛点。以下先具体讲解这个类的实现,而后在讨论如何使用
1. __call__ 函数签名,*_ 代表忽略变长的位置参数,只接受命名参数。实际的装饰器中,一般都是使用命名参数.代码可读性高
2. __call__ 本身的实现逻辑委托给了 do_call 方法,主要是考虑, BaseDecorator 作为装饰基类,需要提供某些工具方法及可扩展方法,但是__ call__ 方法本身无法被继承,所以我们退而求次,将工具方法封装在自定义方法中,子类还是需要重新
实现__ call__, 并调用 do_call 方法, do_call 方法的签名和__ call__ 相同
3. functools提供了 wraps 装饰器, 以上我们分析过python是使用装饰后的函数对象替换之前的函数对象达到装饰的效果, 可能有人会有疑问,如果 之前的函数对象有一些自定义属性呢? 装饰后的新函数会不会丢掉,答案是肯定的, 我们可以访问之前的函数对象,给其设置属性,
这些属性会被存储在 对象的__ dict__ 字典中, 而wraps 装饰器会把原函数的__ dict__拷贝到新的装饰后的函数对象中, 因此 wraps 装饰后,就不会丢掉原有的属性, 而不使用则一定会丢掉。 感兴趣的读者可以点开 wraps 装饰器,看一下具体实现逻辑
4. 在本节开始,我们提出装饰器的通用需求,其中之一是需要将装饰器的参数存放到被装饰的函数中,_add_dict方法便是将装饰器参数设置到原函数以及装饰后的函数中
5. invoke 负责实现具体的装饰逻辑,例如日志装饰器仅仅是打印日志,那么该方法实现就是打印日志,以及调用原函数。 文件锁装饰器,则需要先获取锁后在执行原函数,具体的装饰逻辑在该方法中实现, 具体的装饰器子类应该重写该方法。下一节我们继承该BaseDecorator重写以上的日志及文件锁装饰器
6. invoke 方法是装饰函数调用时被触发的, 而 wrapper 方法只会被触发一次,当 python 解释器执行到@log时,会执行该装饰器的wrapper 方法。相当于,函数被定义的时候,执行了 wrapper方法,在该方法内可以实现某些注册功能。将函数和某些键值映射起来放到字典中,例如 web 框架的 url和handler映射
关系的注册
BaseDecorator вытаскивает вызов, а цель оболочки - позволить декораторам подкласса расширяться в этих двух измерениях для реализации оформления и некоторой логики регистрации соответственно.В следующем разделе мы попытаемся переписать декораторы журнала и блокировки файлов, что более интуитивно понятно. Почувствуйте удобство, которое предоставляет нам BaseDeceator
4.2 Журнал перезаписи и декоратор блокировки файлов
class _log(BaseDec):
def invoke(self, func, *args, **kwargs): #@1
print("execute done:%s, %s" % (func.__name__,func.desc) ) #@2
return func(*args, **kwargs)
def __call__(self, desc):
return self.do_call(desc=desc)
log = _log() #@2
1. invoke方法中包括原函数以及原函数的输入参数,该输入参数不是装饰器的参数信息
2. 通过 func 可以访问到装饰器中定义的 desc 参数信息
3. 创建装饰器实例, 便可以像之前一样使用 @log,需要注意的是,该装饰类变成单例, 在定义装饰逻辑的时候,不要轻易在 self 中储存变量
Переписав декоратор логов, мы видим, что избавились от кошмара трехслойных функций, и успешно разделили базовый код декоратора и код логики декорации, можно больше сосредоточиться на написании основного кода декорации. логика.Функция обращается к параметрам, введенным в декораторе, например, вы можете получить доступ к описанию декоратора лога Далее мы переписываем декоратор файловой блокировки
class _file_lock(BaseDec):
def invoke(self, func, *args, **kwargs):
name = func.name #@1
lk = Lock(name, True)
acquire = lk.acquire()
if not acquire:
print("failed to acquire lock:%s,now ignore" % name)
return
print("acquire process lock:%s" % name)
try:
return func(*args, **kwargs)
finally:
lk.release()
print("release process lock:%s" % name)
def __call__(self, name, block=True):
return self.do_call(name=name, block=block) #@2
file_lock = _file_lock() #@3
1. 可以通过 func 访问到装饰器中定义的 name 参数
2. 把参数传给 do_call 委托执行
3. 创建文件锁实例,其他位置就可以使用@file_lock了
После использования нового базового класса декоратора очень легко и удобно написать новый подкласс декоратора, не нужно ходить на цыпочках для определения сложных трехслойных функций, не нужно повторно задавать параметры декоратора, если у нас большое количество проектов в проект Используя декораторы, вы могли бы также использовать декорирование базовых классов для унификации общих функциональных требований. Читатели должны открыть для себя больше возможностей декораторов, но студенты, знакомые с java Вы должны быть знакомы с понятием аоп.Я много лет мучаюсь с java,и тоже отдаю некоторое предпочтение аоп.На мой взгляд декоратор питона это комбинация аннотаций в java и аоп. В следующем разделе мы сравним сходство между аннотациями java и декораторами python по горизонтали и продемонстрируем аргумент, который мы оставили в начале статьи.
5. Сравнение аннотаций Java
Причина сравнения аннотаций java заключается в том, что автор хочет получить некоторые ссылки и ссылки из некоторых применений java, чтобы мы могли применить их к python.Благодаря сравнению двух языков мы можем глубже понять добавление дизайнеров языка эту функцию, чтобы лучше использовать эту функцию. Что еще более важно, давайте с большей инклюзивностью смотреть на сходства и различия разных языков, сравнивать и думать с точки зрения оценки, что очень полезно для нас, чтобы быстро осваивать новые языки. Этот раздел ни в коем случае Чтобы спорить о плюсах и минусах двух языков, я не хочу провоцировать языковую войну
Возможно, самое интуитивное сходство между декораторами и аннотациями — это символ @at, а использование того же символа в python — своего рода «забота» о программистах на Java. Поскольку Java-программисты имеют особую одержимость аннотациями, сторонние фреймворки используют великолепные аннотации, чтобы помочь Java-программистам реализовать магические функции. И декораторы тоже могут выполнять эту работу
Сама аннотация Java представляет собой просто конфигурацию метаданных.До аннотации, если та же конфигурация метаданных может быть достигнута только с помощью конфигурации xml, после аннотации мы можем объединить конфигурацию метаданных и код, что более интуитивно понятно, и его легче модифицировать Что касается некоторых людей, которые говорят, что конфигурация xml может сохранить компиляцию и упаковку, на самом деле в проекте, который я испытал, будь то изменение кода или изменение конфигурации, необходимо пройти процесс выпуска Опять же, строго запрещается напрямую изменять конфигурацию и перезапускать программу (кроме Особого случая).
Аннотации и интерпретаторы аннотаций неотделимы друг от друга. После определения аннотации вы должны сначала подумать о том, как определить интерпретатор, прочитать конфигурацию метаданных в аннотации и использовать конфигурацию метаданных для чего.
Наиболее распространенный способ его использования — использовать аннотации для регистрации некоторых компонентов и включения определенной функции.Например, используйте Component для регистрации bean-компонентов в spring, используйте RequestMapping для регистрации сопоставления веб-адресов, junit использует Test для регистрации тестовых случаев и Spring. boot использует EnableXXX для открытия некоторых функций расширений и т. д., интерпретатор аннотаций сначала должен получить Объект Class использует отражение для получения конфигурации метаданных в аннотации, а затем реализует логику «регистрации» и «переключения». В базовом классе интерпретатора, который мы реализовали выше, мы также реализовали аналогичную функцию. Мы храним параметры декоратора в конкретном объекте функции, что фактически эквивалентно конфигурации метаданных аннотации. Читатель также может расширить и добавить тег , отмечая, что объект функции действительно декорирован декоратором. Таким образом, некоторые функции регистрации или переключения могут быть реализованы так же просто, как в java.
Кроме того, аннотации настраиваются как метаданные и могут использоваться как аспекты АОП, поэтому аннотации широко используются. Аннотации можно настраивать для классов, свойств и методов. Функция «регистрации» обычно настраивается для классов. использовать аспект аннотации, вам необходимо настроить аннотацию для метода. Ниже перечислены функции, которые могут быть реализованы с помощью аннотации aop.
1. 异常拦截 在使用该注解的函数切面上,将异常拦截住,可以做一些通用的功能,例如异常上报,异常兜底,异常忽略等
2. 权限控制, 日志记录。 可以控制注解方法的切面的用户访问权限,也可以记录用户操作
3. 自动重试, 异步处理。如果我们希望异步调用某方法,或者某些需要异常重试的方法,可以使用注解定义切面, 添加异步或重试处理
Аннотации обеспечивают очень гибкий способ определения аспектов. Вышеприведенные три — это просто распространенные способы их использования. Когда аннотации определяют аспекты, aop заменяет прокси-класс, добавляет некоторую прокси-логику и отбрасывает лежащие в основе принципы реализации. Это разница между этим механизмом и декоратором python не очень большая.Декоратор и режим прокси в режиме дизайна очень похожи.Функции, которые могут быть реализованы приведенными выше аннотациями, могут быть реализованы декораторами python одним путем один. Декоратор вступает в силу, когда функция определена, и aop также проксируется перед фактическим вызовом во время компиляции или во время выполнения. Сам декоратор Python также является функцией, которая помогает нам реализовать декорирование с помощью синтаксического сахара, в то время как статически типизированный java выбирает более сложные методы, такие как динамическая модификация байт-кода и переплетение компилятора для достижения аналогичных функций. Различные базовые реализации не влияют на использование методов и сценариев для обучения друг друга. Так что я все еще думаю Декоратор больше похож на комбинацию аннотации java + aop. Это сравнение может быть легче понять для java-программ, и лучше использовать декораторы.
Дополнительные материалы интервью по Java (операционная система, сеть, zk, mq, redis, java и т. д.):GitHub.com/ с Ха Цяном 12…