2

I'm implementing an "engine" class (described below in detail) and I'm not sure what kind of object to use. I've tried doing a little reading on OO patterns but I'm still not sure. I think my question is language agnostic, but fwiw I'm using Python.

I want to make a class that gets some initialization (e.g. a database connection and some other configuration) and then it can be called repeatedly to process bits of info. For the bits of info, I've broken up my logic into a bunch of methods, but now I have a huge calling signature for each method because I need to pass all kinds of things into each one.

The calling code will look something like this:

db = get_a_db_connection()
my_engine = Engine(db, config)
while True:
  my_info = get_info_from_somewhere()
  my_engine.process_info(my_info)

And the actual Engine class as I have it looks something like this:

class Engine(object):

  def __init__(self, db, config):
    self.db = db
    # Also store the config - it's a little more complicated than
    # this but I am abstracting away details that don't seem needed
    self.config = config

  def process_info(self, info):
    foo = self.method1(info)
    bar = self.method2(info, foo)
    baz = self.method3(info, bar)
    qux = self.method4(info, foo, bar, baz) 
    bla = self.method5(info, bar, baz, qux)

  def method1(self, info):
    # Do something and return intermediate info
    return some_transformation_on_info

  # Definitions for method2 - method5 (and more) follow

  def method2(self, info, foo):
    ...

  <snip>

It seems like it'd be nice to be able to store those intermediate things as attributes so I don't need to pass them as parameters every time. But it doesn't seem appropriate to store them as attributes since they are specific to a piece of info and not the class as a whole.

Is this a case where I use the factory pattern to create an intermediate object that actually does the processing of info?

2
  • 2
    your example screams for being simplified by just inlining everything that method1 etc. do into the calling method process_info! Commented Jul 10, 2014 at 21:15
  • I ended up implementing a factory class. I put all the interesting logic inside a second class (called EngineRun, meaning an instance of this is a single 'run' through the Engine, although I don't really like the name). The Engine class instantiates a new EngineRun and calls the process() method. Since the instance is short lived it is free to make all of these intermediate values instance attributes and therefore it doesn't muck around in the Engine class namespace. Commented Jul 23, 2014 at 20:19

3 Answers 3

3

It much depends on the logic of the parameters. But you can consider defining a binding object which has two attributes: an engine and a info. Then you move all these function on the binding object.

Sign up to request clarification or add additional context in comments.

1 Comment

I sort-of did this. I posted a longer description above as a child to my question, but basically I made a child class (EngineRun) that holds all the intermediate info as instance attributes so I don't need to pass around so much stuff. Thanks!
0

You could pass an environment around:

class Engine(object):

  def __init__(self, db, config):
    self.db = db
    self.config = config

  def process_info(self, info):
    env = {'info': info}
    self.method1(env)
    self.method2(env)
    self.method3(env)
    self.method4(env)
    self.method5(env)

  def method1(self, env):
    env['foo'] = some_transformation_on_info(env['info'])

  def method2(self, env):
    env['bar'] = something_from(env['foo'])

  def method3(self, env):
    env['baz'] = my_func(env['bar'])

  def method4(self, env):
    env['qux'] = your_func(env['foo'], env['bar'], env['baz'])

  def method5(self, env):
    env['bla'] = your_func(env['bar'], env['baz'], env['qux'])

That way, process_info() doesn't need to know what's going on in all the methods it calls.

If you don't like the dictionary subscription syntax, you can do this:

class Environment(object):
    pass

class Engine(object):

  def __init__(self, db, config):
    self.db = db
    self.config = config

  def process_info(self, info):
    env = Environment()
    env.info = info
    self.method1(env)
    self.method2(env)
    self.method3(env)
    self.method4(env)
    self.method5(env)

  def method1(self, env):
    env.foo = some_transformation_on_info(env.info)

  def method2(self, env):
    env.bar = something_from(env.foo)

  def method3(self, env):
    env.baz = my_func(env.bar)

  def method4(self, env):
    env.qux = your_func(env.foo, env.bar, env.baz)

  def method5(self, env):
    env.bla = your_func(env.bar, env.baz, env.qux)

1 Comment

This would absolutely work - although I ended up going with a different method as posted above. Thanks for the idea. It might be a good one in a different scenario.
-1
class EngineInfoProcessor(object):

    def __init__(self, engine, info):
        self.engine = engine
        self.info = info

    def process(self):
        foo = self.engine.method1(info)
        self.foo = foo # if you want
        yield foo # if you want
        bar = self.method2(info, foo)
        self.bar = bar # ...
        yield bar # ...
        baz = self.method3(info, bar)
        self.baz = baz
        yield baz
        qux = self.method4(info, foo, bar, baz) 
        self.qux = qux
        yield qux
        bla = self.method5(info, bar, baz, qux)
        self.bla = bla
        yield bla

might be what you want.

Comments

Your Answer

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.