5
\$\begingroup\$

I'm reading the awesome Head First Design Patterns book. As an exercise I converted first example (or rather a subset of it) to Python. The code I got is rather too simple, i.e. there is no abstract nor interface declarations, it's all just 'classes'. Is that the right way to do it in Python? My code is below, original Java code and problem statement can be found at http://books.google.com/books?id=LjJcCnNf92kC&pg=PA18

class QuackBehavior():
 def __init__(self):
 pass
 def quack(self):
 pass
class Quack(QuackBehavior):
 def quack(self):
 print "Quack!"
class QuackNot(QuackBehavior):
 def quack(self):
 print "..."
class Squeack(QuackBehavior):
 def quack(self):
 print "Squeack!"
class FlyBehavior():
 def fly(self):
 pass
class Fly():
 def fly(self):
 print "I'm flying!"
class FlyNot():
 def fly(self):
 print "Can't fly..."
class Duck():
 def display(self):
 print this.name
 def performQuack(self):
 self.quackBehavior.quack()
 def performFly(self):
 self.flyBehavior.fly()
class MallardDuck(Duck):
 def __init__(self):
 self.quackBehavior = Quack()
 self.flyBehavior = Fly()
if __name__ == "__main__":
 mallard = MallardDuck()
 mallard.performQuack()
 mallard.performFly()
 mallard.flyBehavior = FlyNot()
 mallard.performFly()
asked Feb 22, 2013 at 17:46
\$\endgroup\$
1
  • \$\begingroup\$ This looked very familiar - you might want to take a look at my answer to that question. \$\endgroup\$ Commented Feb 24, 2013 at 20:04

2 Answers 2

7
\$\begingroup\$

In Python, you can pass functions as argument. This simplifies the "Strategy" Design pattern, as you don't need to create classes just for one method or behavior. See this question for more info.

def quack():
 print "Quack!"
def quack_not():
 print "..."
def squeack():
 print "Squeack!"
def fly():
 print "I'm flying!"
def fly_not():
 print "Can't fly..."
class Duck:
 def display(self):
 print this.name
 def __init__(self, quack_behavior, fly_behavior):
 self.performQuack = quack_behavior
 self.performFly = fly_behavior
class MallardDuck(Duck):
 def __init__(self):
 Duck.__init__(self, quack, fly)
if __name__ == "__main__":
 duck = Duck(quack_not, fly_not)
 duck.performQuack()
 mallard = MallardDuck()
 mallard.performQuack()
 mallard.performFly()
 mallard.performFly = fly_not
 mallard.performFly()

Output:

...
Quack!
I'm flying!
Can't fly...
answered Feb 22, 2013 at 23:35
\$\endgroup\$
2
  • \$\begingroup\$ I picked this answer because it actually shows what @WinstonEwert's only proposed. However, this code lets you create a generic Duck, which was not possible in original Java example (that class is abstract). I assumed not having __init__ in Duck() would make it kind-of-abstract in Python... Is that a correct assumption? \$\endgroup\$ Commented Feb 23, 2013 at 15:08
  • \$\begingroup\$ Yes, here's some more info on that: fw-geekycoder.blogspot.com/2011/02/… The reason I had the __init__ was for my own reasons of testing the script. \$\endgroup\$ Commented Feb 25, 2013 at 23:27
8
\$\begingroup\$
class QuackBehavior():

Don't put () after classes, either skip it, or put object in there

 def __init__(self):
 pass

There's no reason to define a constructor if you aren't going to do anything, so just skip it

 def quack(self):
 pass

You should probably at least raise NotImplementedError(), so that if anyone tries to call this it'll complain. That'll also make it clear what this class is doing.

You don't really need this class at all. The only reason to provide classes like this in python is documentation purposes. Whether or not you think that's useful enough is up to you.

class Quack(QuackBehavior):
 def quack(self):
 print "Quack!"
class QuackNot(QuackBehavior):
 def quack(self):
 print "..."
class Squeack(QuackBehavior):
 def quack(self):
 print "Squeack!"
class FlyBehavior():
 def fly(self):
 pass
class Fly():

If you are going to defined FlyBehavior, you should really inherit from it. It just makes it a litle more clear what you are doing.

 def fly(self):
 print "I'm flying!"
class FlyNot():
 def fly(self):
 print "Can't fly..."
class Duck():

I'd define a constructor taking the quack and fly behavior here.

 def display(self):
 print this.name
 def performQuack(self):
 self.quackBehavior.quack()
 def performFly(self):
 self.flyBehavior.fly()
class MallardDuck(Duck):
 def __init__(self):
 self.quackBehavior = Quack()
 self.flyBehavior = Fly()

There's not really a reason for this to be a class. I'd make a function that sets up the Duck and returns it.

if __name__ == "__main__":
 mallard = MallardDuck()
 mallard.performQuack()
 mallard.performFly()
 mallard.flyBehavior = FlyNot()
 mallard.performFly()
answered Feb 22, 2013 at 18:35
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.