Strategy pattern
From wikinotes
The strategy pattern has a couple of very abstract goals:
- facilitate maintenance/usage (do not worry about adding method to base-class)
- sharing methods between subclasses at the same inheritance-level (without mixins)
- compartmentalize reusable behaviours
- simpler to test
- less prone to cyclical imports :)
Problem
Say that you wanted to add the identical method
self.fly()
to bothGrandChildA1() and GrandChildB1()
only. Or, say that you wanted to addself.fly()
toParent()
- but different subclasses would need different implementations.
Parent() | +----------------+-------------------+ | | ChildA() ChildB() | | | | +--------+--------+ +------+-------+ | | | | GrandChildA1() GrandChildA2() GrandChildB1() GrandChildB2()In the inheritance diagram above,
- It is easy to introduce behaviour to Parent() that will break other classes
- If you wanted to re-use code horizontally (ex:
GrandChildA1()
andGrandChildB1()
only) you would need to create a confusing mixin class.
Solution
The Strategy Pattern uses parameters to solve the issue. Each IFlyBehaviour() has it's own method self.fly(). This object's fly() is called by the object.
Parent() | | | +--------------------------+-------------------------+ | | ChildA() FlyBehaviour() ChildB() | NoFly() | | JetFly() | +--------+------------------+ WingFly() +------+-----------------+ | | | | GrandChildA1(IFlyBehaviour.NoFly) GrandChildA2() GrandChildB1(IFlyBehaviour.NoFly) GrandChildB2()This solution has some side-benefits as well:
- easy to know all handled FlyBehaviours in all classes
- do you still need ChildA/subclasses GrandChildA1/GrandChildB2? Can this be solved with a single class now?
- This is Dependency Injection. Easier to test, less prone to cyclical imports.
Example:
# flybehaviours.py class FlyBehaviour(object): """ Base-Class for FlyBehaviours """ __metaclass__ = abc.ABCMeta def fly(self): raise NotImplementedError() class NoFly(FlyBehaviour): def fly(self): return 'walking' class JetFly(FlyBehaviour): def fly(self): return 'whooshing' class WingFly(FlyBehaviour): def fly(self): return 'flapping' parent = Parent(flybehaviours.NoFly())