Ответ 1
Пример в Python не так отличается от других. Чтобы издеваться над PHP script:
class StrategyExample:
def __init__(self, func=None):
if func:
self.execute = func
def execute(self):
print("Original execution")
def executeReplacement1():
print("Strategy 1")
def executeReplacement2():
print("Strategy 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat2 = StrategyExample(executeReplacement2)
strat0.execute()
strat1.execute()
strat2.execute()
Вывод:
Original execution
Strategy 1
Strategy 2
Основные отличия:
- Вам не нужно писать какой-либо другой класс или реализовывать какой-либо интерфейс.
- Вместо этого вы можете передать ссылку на функцию, которая будет привязана к методу, который вы хотите.
- Функции могут по-прежнему использоваться отдельно, и исходный объект может иметь поведение по умолчанию, если вы хотите (для этого может использоваться шаблон
if func == None
). - Действительно, он чист, как обычно, короткий и элегантный с Python. Но вы теряете информацию; без явного интерфейса, программист считается взрослым, чтобы знать, что они делают.
Обратите внимание, что есть три способа динамического добавления метода в Python:
-
То, как я показал тебе. Но метод будет статическим, он не получит переданный аргумент "self".
-
Использование имени класса:
StrategyExample.execute = func
Здесь весь экземпляр получит func
как метод execute
и получит в качестве аргумента self
.
-
Связывание только с экземпляром (с использованием модуля
types
):strat0.execute = types.MethodType(executeReplacement1, strat0)
или с Python 2 также требуется класс изменяемого экземпляра:
strat0.execute = types.MethodType(executeReplacement1, strat0, StrategyExample)
Это привяжет новый метод к strat0
и только strat0
, как в первом примере. Но start0.execute()
получит self
в качестве аргумента.
Если вам нужно использовать ссылку на текущий экземпляр в функции, то вы бы объединили первый и последний методы. Если вы этого не сделаете:
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = func
def execute(self):
print(self.name)
def executeReplacement1():
print(self.name + " from execute 1")
def executeReplacement2():
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
Вы получите:
Traceback (most recent call last):
File "test.py", line 28, in <module>
strat1.execute()
File "test.py", line 13, in executeReplacement1
print self.name + " from execute 1"
NameError: global name 'self' is not defined
Таким образом, правильный код будет:
import sys
import types
if sys.version_info[0] > 2: # Python 3+
create_bound_method = types.MethodType
else:
def create_bound_method(func, obj):
return types.MethodType(func, obj, obj.__class__)
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = create_bound_method(func, self)
def execute(self):
print(self.name)
def executeReplacement1(self):
print(self.name + " from execute 1")
def executeReplacement2(self):
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
Это приведет к ожидаемому результату:
Strategy Example 0
Strategy Example 1 from execute 1
Strategy Example 2 from execute 2
Конечно, в случае, если функции больше не могут использоваться автономно, но все равно могут быть привязаны к любому другому экземпляру любого объекта без каких-либо ограничений интерфейса.