Strategy Pattern TestDriver

Here is a simple driver that tests the code I posted here: https://jasonjkeller.wordpress.com/2013/01/25/my-strategy-pattern-strategy/

__author__ = ‘jasonjkeller’

from GodzillaSim import *

def main():

godzilla = Godzilla()
godzilla.performDeclare()
godzilla.performMove()
godzilla.performAttacks()

mothra = Mothra()
mothra.performDeclare()
mothra.performMove()
mothra.performAttacks()

civilian = Civilian()
civilian.performDeclare()
civilian.performMove()

military = Military()
military.performDeclare()
military.performMove()
military.performAttacks()

battleship = Battleship()
battleship.performDeclare()
battleship.performMove()
battleship.performAttacks()

tank = Tank()
tank.performDeclare()
tank.performMove()
tank.performAttacks()
boat = Boat()
boat.Display()

building = Building()
building.Display()

tree = Tree()
tree.Display()

oceanbg = OceanBG()
oceanbg.Display()

citybg = CityBG()
citybg.Display()

main()

 

 

Here is the output produced by the driver:

 

/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python /Users/jasonjkeller/PycharmProjects/GodzillaSim/GodzillaSimDriver.py
Godzilla declares: ROOOAAAAAR!!!
I’m walking around!
I’m breathing fire at you!
Mothra declares: BZZZzzz!!!
I’m flying around!
I’m shooting a laser beam at you!
Civilian declares: Run for your life!!!
I’m running away!
Military declares: Fire your weapons!!!
I’m walking around!
I’m shooting my gun at you!
Battleship declares: Fire your battleship weapons!!!
I’m floating around!
I’m shooting my gun at you!
Tank declares: Fire your tank cannon!!!
I’m driving around!
I’m shooting my gun at you!
I am an inanimate boat.
I am an inanimate building.
I am an inanimate tree.
I am an Ocean location.
I am a City location.

Process finished with exit code 0

Advertisements

My “Strategy Pattern” Strategy

EDIT: Sorry, I can’t seem to get my code to paste into this blog while keeping the spacing and indentation that I use in PyCharm. 😦

I’m not sure if I’m generalizing too much or not, but I saw an opportunity to utilize the strategy pattern by creating a few interfaces (classes) that implement shared, but different, behaviors for almost all of my animate classes. For instance, I currently have the following animate classes: Monster (subclasses: Godzilla, Mothra), People (subclasses: Civilian, Military), and Vehicles (subclasses: Battleship, Tank). Each class implements all of the following interfaces (with the exception being that Civilians don’t attack at all): MoveBehavior (different ways of moving around), AttackBehavior (different ways of attacking), and DeclareBehavior (different ways of talking or declaring themselves). Within each of those interfaces is different methods for achieving the actions of moving, attacking, and declaring (in an audible manner) themselves.

One thing I don’t really understand is how to implement my inanimates and locations. Being that we’re using OO programming my first instinct is to create a class for each so I ended up with the following classes:

Inanimates: Boat, Building, Tree

Locations: Ocean, City

Being that I don’t really know what else to do with these, I simply created a Display method in each class which prints a line of text saying what they are. The locations are meant to simply be backgrounds, as are the three inanimates, with the exception that I want the three inanimates (Boat, Building, Tree) to be destroyable by Godzilla either breathing fire or punching them.

This leads me to one issue with my AttackBehavior interface, I wanted to have two subclasses AttackFireBreath and AttackPunch that could both be utilized by Godzilla. I’m not sure if it’s possible to have Godzilla choose the appropriate behavior based on context if I’m using a simple interface. For instance in the Godzilla class (subclass of Monster) I currently just have self.attackBehavior = AttackFireBreath() but if I also implemented self.attackBehavior = AttackPunch() then how do I get him to choose between the two? Say I want him to breath fire at trees, boats, people but punch Mothra, battleships, buildings, and tanks. Can I do that with how I currently have the interface set up? Is it something that can be implemented by using the Observer pattern?

Here’s a copy of my current code:

__author__ = ‘jasonjkeller’

 
#interface for move behaviors
class MoveBehavior(object):
def move(self):
pass

class MoveWalk(MoveBehavior):
def move(self):
print “I’m walking around!”

class MoveRunAway(MoveBehavior):
def move(self):
print “I’m running away!”

class MoveFly(MoveBehavior):
def move(self):
print “I’m flying around!”

class MoveFloat(MoveBehavior):
def move(self):
print “I’m floating around!”

class MoveDrive(MoveBehavior):
def move(self):
print “I’m driving around!”

 
#interface for attack behaviors
class AttackBehavior(object):
def attack(self):
pass

class AttackFireBreath(AttackBehavior):
def attack(self):
print “I’m breathing fire at you!”

class AttackLaserBeam(AttackBehavior):
def attack(self):
print “I’m shooting a laser beam at you!”

class AttackPunch(AttackBehavior):
def attack(self):
print “I’m punching you!”

class AttackShootGun(AttackBehavior):
def attack(self):
print “I’m shooting my gun at you!”

 

 

#interface for declare behaviors
class DeclareBehavior(object):
def declare(self):
pass

class DeclareGodzilla(DeclareBehavior):
def declare(self):
print “Godzilla declares: ROOOAAAAAR!!!”

class DeclareMothra(DeclareBehavior):
def declare(self):
print “Mothra declares: BZZZzzz!!!”

class DeclareCivilian(DeclareBehavior):
def declare(self):
print “Civilian declares: Run for your life!!!”

class DeclareMilitary(DeclareBehavior):
def declare(self):
print “Military declares: Fire your weapons!!!”

class DeclareBattleship(DeclareBehavior):
def declare(self):
print “Battleship declares: Fire your battleship weapons!!!”

class DeclareTank(DeclareBehavior):
def declare(self):
print “Tank declares: Fire your tank cannon!!!”

 

# Monster superclass
class Monster(object):
moveBehavior = MoveBehavior()
attackBehavior = AttackBehavior()
declareBehavior = DeclareBehavior()
def setMoveBehavior(self, cb):
self.moveBehavior = cb

def setAttackBehavior(self, ab):
self.attackBehavior = ab

def setDeclareBehavior(self, yb):
self.declareBehavior = yb

def display(self):
pass

def performMove(self):
self.moveBehavior.move()

def performAttacks(self):
self.attackBehavior.attack()

def performDeclare(self):
self.declareBehavior.declare()

def isDead(self):
pass

class Godzilla(Monster):
“””a subclass of Monster”””
def __init__(self):

self.attackBehavior = AttackFireBreath()
self.moveBehavior = MoveWalk()
self.declareBehavior = DeclareGodzilla()

def display(self):
print “I’m Godzilla!!!”

class Mothra(Monster):
“””a subclass of Monster”””
def __init__(self):

self.attackBehavior = AttackLaserBeam()
self.moveBehavior = MoveFly()
self.declareBehavior = DeclareMothra()

def display(self):
print “I’m Mothra!!!”

 

 

# People superclass
class People(object):
moveBehavior = MoveBehavior()
attackBehavior = AttackBehavior()
declareBehavior = DeclareBehavior()
def setMoveBehavior(self, cb):
self.moveBehavior = cb

def setAttackBehavior(self, ab):
self.attackBehavior = ab

def setDeclareBehavior(self, yb):
self.declareBehavior = yb

def display(self):
pass

def performMove(self):
self.moveBehavior.move()

def performAttacks(self):
self.attackBehavior.attack()

def performDeclare(self):
self.declareBehavior.declare()

def isDead(self):
pass

class Civilian(People):
“””a subclass of People”””
def __init__(self):

self.moveBehavior = MoveRunAway()
self.declareBehavior = DeclareCivilian()

def display(self):
print “We’re just civilians!!!”

class Military(People):
“””a subclass of People”””
def __init__(self):

self.moveBehavior = MoveWalk()
self.attackBehavior = AttackShootGun()
self.declareBehavior = DeclareMilitary()

def display(self):
print “We’re the military!!!”

 
# Vehicle superclass
class Vehicle(object):
moveBehavior = MoveBehavior()
attackBehavior = AttackBehavior()
declareBehavior = DeclareBehavior()
def setMoveBehavior(self, cb):
self.moveBehavior = cb

def setAttackBehavior(self, ab):
self.attackBehavior = ab

def setDeclareBehavior(self, yb):
self.declareBehavior = yb

def display(self):
pass

def performMove(self):
self.moveBehavior.move()

def performAttacks(self):
self.attackBehavior.attack()

def performDeclare(self):
self.declareBehavior.declare()

def isDead(self):
pass

class Battleship(Vehicle):
“””a subclass of Vehicle”””
def __init__(self):

self.moveBehavior = MoveFloat()
self.attackBehavior = AttackShootGun()
self.declareBehavior = DeclareBattleship()

def display(self):
print “I’m a battleship!!!”

class Tank(Vehicle):
“””a subclass of Vehicle”””
def __init__(self):

self.moveBehavior = MoveDrive()
self.attackBehavior = AttackShootGun()
self.declareBehavior = DeclareTank()

def display(self):
print “I’m a tank!!!”

 
# inanimate classes
class Boat(object):
def Display(self):
print “I am an inanimate boat.”

class Building(object):
def Display(self):
print “I am an inanimate building.”

class Tree(object):
def Display(self):
print “I am an inanimate tree.”

class OceanBG(object):
def Display(self):
print “I am an Ocean location.”

class CityBG(object):
def Display(self):
print “I am a City location.”

My CIS 211 Project: Godzilla Simulation!!!

For my CIS 211 project I wish to create a simulation based on Godzilla. My goal is to have a few different locations in which Godzilla engages various animate and inanimate objects in combat and wanton destruction.

For my Animates category I will have Godzilla as the main focus of the simulation. He will roam around destroying different types of inanimate objects (such as Buildings, Trees and Boats) with his fire breath and punching abilities. He will also engage with several different types of animates (Civilians, Military, Battleships, Mothra) by chasing after them and breathing fire or punching at them.

Mothra will be a monster enemy that will randomly appear and fight with Godzilla. Mothra’s Actions will include the ability to fly around, shoot laser beams at Godzilla, and be killed in battle by Godzilla. Mothra will be able to appear at any location throughout the game.

Battleships (as opposed to inanimate Boats) will be found only at the Ocean location. Their Actions will include the ability to move through the Ocean and fire Guns at Godzilla. They will also be destroyable by Godzilla’s fire breathing and punching actions.

Finally I wish to have several subclasses of People as animate objects. The first subclass is Civilians whose Actions consist of running away from Godzilla, screaming for their lives, and being killed by Godzilla. The second subclass of People is Military. They will have all of the same Actions as Civilians but they will also have the added ability to engage Godzilla by firing their guns at him. All subclasses of People will only be able to appear in the City location.

My Inanimates will consist of Buildings, Boats, Trees, and Guns. Buildings, Trees and Boats will be scattered throughout the locations of the simulation and will be destroyable by the fire breathing and punching actions of Godzilla. Guns will be equipped on the Military subclass of People and they will be able to be fired at Godzilla when engaged with him.

My Locations will consist of a City and an Ocean. The City (likely modeled after Tokyo) will be filled with Buildings, Trees, and People. The Ocean will consist of Battleships and Boats.

I’m optimistic that this project will be both attainable and highly enjoyable but I’m also keenly aware that there are a myriad of implementation issues that haven’t even begun to creep into my consciousness yet. More than anything I’m excited to attempt to build a simulation like this from the ground up as I fully expect it to be a rewarding learning experience.

Reflections on Porting SimUDuck

I feel that I have a better grasp on basic Java programming having gone through the process of porting SimUDuck to Python. Java seems a lot “wordier” to me in it’s use of syntax. Having such a limited background in programming – my only real exposure being three months of Python in CIS 210 – I feel that Java is a bit more confusing due to the wordier and more restrictive syntax but overall it’s not terribly different than Python. My brain certainly got twisted around numerous times jumping back and forth between the two languages but I’m confident that over time each of them will become more ingrained through the conversion process.

Cooking with the Strategy Pattern

Here’s a brief checklist on how to implement the strategy pattern:

1. Determine what aspects of your program vary versus which aspects are static.

2. Encapsulate the aspects that vary by creating interfaces/classes for each of them.

3. Program to the encapsulated interfaces/classes rather than implementing those aspects locally.

4. Strive to utilize composition over inheritance as much as possible to keep your code as flexible and maintainable as possible.

SimUDuck.py

__author__ = 'jasonjkeller'
 
class FlyBehavior(object):
def fly(self):
pass
class FlyNoWay(FlyBehavior):
def fly(self):
print "I can't fly"
class FlyRocketPowered(FlyBehavior):
def fly(self):
print "I'm flying with a rocket"
class FlyWithWings(FlyBehavior):
def fly(self):
print "I'm flying!!"
 
class QuackBehavior(object):
def quack(self):
pass
class Quack(QuackBehavior):
def quack(self):
print "Quack"
class FakeQuack(QuackBehavior):
def quack(self):
print "Qwak"
class MuteQuack(QuackBehavior):
def quack(self):
print "<< Silence >>"
class Squeak(QuackBehavior):
def quack(self):
print "Squeak"
 
class Duck(object):
flyBehavior = FlyBehavior()
quackBehavior = QuackBehavior()
def setFlyBehavior(self, fb):
self.setFlyBehavior = fb
def setQuackBehavior(self, qb):
self.setQuackBehavior = qb
def Display(self):
pass
def performFly(self):
self.flyBehavior.fly()
def performQuack(self):
self.quackBehavior.quack()
def swim(self):
print "All ducks float, even decoys!"

class MallardDuck(Duck):
def __init__(self):
self.quackBehavior = Quack()
self.flyBehavior = FlyWithWings()
def Display(self):
print "I'm a real Mallard duck"
class DecoyDuck(Duck):
def __init__(self):
self.quackBehavior = MuteQuack()
self.flyBehavior = FlyNoWay()
def Display(self):
print "I'm a duck Decoy"
class ModelDuck(Duck):
def __init__(self):
self.quackBehavior = Quack()
self.flyBehavior = FlyNoWay()
def Display(self):
print "I'm a model duck"
class RubberDuck(Duck):
def __init__(self):
self.quackBehavior = Squeak()
self.flyBehavior = FlyNoWay()
def Display(self):
print "I'm a rubber duckie"
class RedHeadDuck(Duck):
def __init__(self):
self.quackBehavior = Quack()
self.flyBehavior = FlyWithWings()
def Display(self):
print "I'm a real Red Headed duck"
 
def main():
mallard = MallardDuck()
rubberDuckie = RubberDuck()
decoy = DecoyDuck()
model = ModelDuck()
mallard.performQuack()
rubberDuckie.performQuack()
decoy.performQuack()
model.performFly()
model.setFlyBehavior(FlyRocketPowered())
model.performFly()
main()

Design Decisions/Tradeoffs of the Strategy Pattern

The benefit of using the strategy pattern is maintainability and extensibility of code as opposed to the reusability of code through inheritance offered by using standard OO design. The problem that Joe faced was that by relying so heavily on inheritance he either had to include excessive attributes/behaviors in the Duck superclass or he had to use duplicate code to create specific attributes/behaviors in every subclass of Duck. In the first scenario he would have to deal with shadowing unused attributes/behaviors every time he encountered a subclass that didn’t use them. In the second scenario he would need to update every subclass each and every time there was a change to an attribute or behavior being used by them. By using the strategy pattern Joe was able to encapsulate things that vary (such as behaviors) and simply reference their interface. This gave him the power to update behaviors and have the changes take effect everywhere the behavior is being used. This also gave him the flexibility to use these behavior interfaces anywhere he wished as they were not specific to any particular class. So even though the strategy pattern involves a bit more complexity when initially being set up, in the long run it makes updating and maintaining your program much easier and more efficient.