The example in Python is not so different of the others. To mock the 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()
This outputs :
Original execution
Strategy 1
Strategy 2
The main differences are :
- You don't need to write any other
class nor implementing any interface.
- Instead you can pass a function reference that will be binded to the method you want.
- So the functions can still be used stand alone, and the original object can have a default behavior if you want to (the
if func == None
can be used for that).
- Indeed, it's clean short and elegant as usual with Python. But you loose information : : no explicit interface, so the programmer is assumed as an adult knowing what is doing.
Note that there is 3 ways to dynamically add a method in Python :
the way I've shown you. But the method will be static, it won't get the "self" argument passed.
using the class name :
StrategyExample.execute = func
Here, all the instance will get "func" as the "execute" method, that will get "self" passed as an argument.
binding to an instance only (using types) :
strat0.execute = types.MethodType(executeReplacement1, strat0, StrategyExample)
This will bind the new method to "start0", and only "strat0" like with the first example. But start0.execute()
will get "self" passed as an argument.
If you need to use a reference to the current instance in the function, then you will combine the first and the last method. If you do not :
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()
You will get :
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
So the proper code would be :
import types
class StrategyExample :
def __init__(self, func=None) :
self.name = "Strategy Example 0"
if func :
self.execute = types.MethodType(func, self, StrategyExample)
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()
This will output the expected result :
Strategy Example 0
Strategy Example 1 from execute 1
Strategy Example 2 from execute 2
Of course in the case the functions cannot be used stand alone anymore, but still can binded to any other instance of any object, without any interface limitation.