How to access fields with StrategyPattern in Python?

110 views Asked by At

I'm trying to use the Strategy Pattern to include different behaviours for different sizes of a simulation.

I came across this implementation from the first example of the book Head First Design Patterns.

However, I don't understand where and how should I access my data initialised in my simulation.

from abc import ABCMeta, abstractmethod
###########################################################################    #####
# Abstract Simulation class and concrete Simulation type classes.
################################################################################

class Simulation:
    def __init__(self, run, plot):
        self._run_behavior = run
        self._plot_behavior = plot

    def run(self):
        return self._run_behavior.run()

    def plot(self):
        return self._plot_behavior.plot()        

class SmallSimulation(Simulation):
    def __init__(self):
        Simulation.__init__(self, Run(), Plot())
        print "I'm a small simulation"
        self.data = 'Small Data'

class BigSimulation(Simulation):
    def __init__(self):
        Simulation.__init__(self, Run(), Plot())
        print "I'm a big simulation"
        self.data = 'Big Data'

class LargeSimulation(Simulation):
    def __init__(self):
        Simulation.__init__(self, RunLarge(), Plot())
        print "I'm a large simulation"
        self.data = 'Large Data'

################################################################################
# Run behavior interface and behavior implementation classes.
################################################################################

class RunBehavior:
    __metaclass__ = ABCMeta
    @abstractmethod 
    def run(self):
        pass

class Run(RunBehavior):
    def run(self):
        print "I'm running standard"
        print self.data

class RunLarge(RunBehavior):
    def run(self):
        print "I'm running multilevel"


################################################################################
# Plot behavior interface and behavior implementation classes.
################################################################################

class PlotBehavior:
    __metaclass__ = ABCMeta
    @abstractmethod 
    def plot(self):
        pass

class Plot(PlotBehavior):
    def plot(self):
        print "I'm plotting results"

################################################################################
# Test Code.
################################################################################

if __name__ == '__main__':
    smallSimulation = SmallSimulation()
    bigSimulation = BigSimulation()
    largeSimulation = LargeSimulation()

    print('='*20)
    print('Execution')
    smallSimulation.run()
    bigSimulation.run()
    largeSimulation.run()

    print('='*20)
    print('Plotting')
    smallSimulation.plot()
    bigSimulation.plot()
    largeSimulation.plot()

The output is

I'm a small simulation
I'm a big simulation
I'm a large simulation
====================
Execution
I'm running standard
Traceback (most recent call last):
  File "strategy.py", line 84, in <module>
    smallSimulation.run()
  File "strategy.py", line 16, in run
    return self._run_behavior.run()
  File "strategy.py", line 52, in run
    print self.data
AttributeError: 'Run' object has no attribute 'data'

How should I initialise and access my data?

1

There are 1 answers

4
NeoWang On BEST ANSWER

Your run class doesn't have a data attribute, hence the exception.

class Run(RunBehavior):
# This class does NOT have a data attribute
    def run(self):
        print "I'm running standard"
        print self.data

To access simulation's data within Run, you can pass it in Run's init():

class Run(RunBehavior):
    def __init__(self, data):
       self.data = data
    def run(self):
       print "I'm running standard"
       print self.data