Implementing chain of responsibility

K

koranthala

Hi,
I want to implement chain of responsibility pattern in Python (for
a Django project)
The problem that I see is a rather odd one - how to link the
subclasses with the super class.

Ex: Suppose the two child classes are as given below (A1, A2 child
classes of A)
class A:
...

class A1(A):
...

class A2(A):
...

Now, I want to call A.method(x) and I want A1 and A2 to act on x.
The ways I could think of till now are
1. have a registry in A. A1 and A2 objects register to A's registry.
Then loop through the registry.
2. loop through A.__subclasses__ to invoke each subclass.

I am leaning towards option 1.

The problem is that A1 and A2 are in different modules from A. So, how
can I make A aware that A1 and A2 are there?
i.e.
The module structure is MA (contains class A), MA1 (contains class A1)
MA2 (contains class A2).
Where do I do import MA1 and MA2 etc so that the register methods of
MA1 and MA2 are hit?
Now, from the code (when I receive a HTTP request), I will be calling
MA.A.method(x) only. So there is no need of importing MA1 and MA2.

Is __init__.py used for this purpose - i.e. just import all the
modules inside __init__.py so that the code is it in each?
 
C

Chris Rebert

Hi,
   I want to implement chain of responsibility pattern in Python (for
a Django project)
   The problem that I see is a rather odd one - how to link the
subclasses with the super class.

Grabbing out my copy of Head First Design Patterns and looking up this
pattern, it sounds like you're going about this the wrong way. From
what I can grok, Chain-of-Responsibility looks like this:

class SomeHandler(object)
def __init__(self, successor=None):
self.successor = successor

def theMethod(self, theRequest):
result = try_and_handle(theRequest)
if did_not_handle(theRequest) and self.successor is not None:
return successor.theMethod(theRequest)
else:
return result

#imagine some other handler classes
#setup:
masterHandler = SomeHandler(OtherHandler(ThirdHandler()))
#usage:
result = masterHandler.theMethod(aRequest)

So the *classes* don't ever know anything about each other; you pass a
handler class an instance of its successor handler at
construction-time. So there's no need for any registry or
introspection at all. You determine the ordering at runtime when you
construct the instances.

Of course, this entire pattern is usually unnecessary in Python as you
can usually write the same thing less verbosely and more
straightforwardly as:
def someHandler(theRequest):
result = try_and_handle(theRequest)
if did_not_handle(theRequest):
return False, None
else:
return True, result

#imagine some other handler functions
#setup:
handlers = [someHandler, otherHandler, thirdHandler]
#usage:
for handler in handlers:
success, result = handler(theRequest)
if success: break

Note the lack of classes and how the sequencing is now made explicit.

Cheers,
Chris
 
K

koranthala

Hi,
   I want to implement chain of responsibility pattern in Python (for
a Django project)
   The problem that I see is a rather odd one - how to link the
subclasses with the super class.

Grabbing out my copy of Head First Design Patterns and looking up this
pattern, it sounds like you're going about this the wrong way. From
what I can grok, Chain-of-Responsibility looks like this:

class SomeHandler(object)
    def __init__(self, successor=None):
        self.successor = successor

    def theMethod(self, theRequest):
        result = try_and_handle(theRequest)
        if did_not_handle(theRequest) and self.successor is not None:
            return successor.theMethod(theRequest)
        else:
            return result

#imagine some other handler classes
#setup:
masterHandler = SomeHandler(OtherHandler(ThirdHandler()))
#usage:
result = masterHandler.theMethod(aRequest)

So the *classes* don't ever know anything about each other; you pass a
handler class an instance of its successor handler at
construction-time. So there's no need for any registry or
introspection at all. You determine the ordering at runtime when you
construct the instances.

Of course, this entire pattern is usually unnecessary in Python as you
can usually write the same thing less verbosely and more
straightforwardly as:
def someHandler(theRequest):
    result = try_and_handle(theRequest)
    if did_not_handle(theRequest):
        return False, None
    else:
        return True, result

#imagine some other handler functions
#setup:
handlers = [someHandler, otherHandler, thirdHandler]
#usage:
for handler in handlers:
    success, result = handler(theRequest)
    if success: break

Note the lack of classes and how the sequencing is now made explicit.

Cheers,
Chris

Hi,
Thank you very much Chris for the extremely quick and helpful
reply.
I agree that it is not perfect CoR as per the examples given. But,
I have done it very similar to the second example that you had given.
I needed classes because I am not doing just one thing - I have a lot
of pre-processing and post processing, so I had used classes. The
register methods etc are just a fancy way of creating the list as you
mentioned. I am using the registry because there are many procedures
wherein different methods of the classes in registry are being used.
I am not sure whether I have understood your points completely. I
still cannot understand how to do the import so that the register
methods are hit.
 
C

Chris Rebert

Hi,
   I want to implement chain of responsibility pattern in Python (for
a Django project)
   The problem that I see is a rather odd one - how to link the
subclasses with the super class.

Grabbing out my copy of Head First Design Patterns and looking up this
pattern, it sounds like you're going about this the wrong way. From
what I can grok, Chain-of-Responsibility looks like this:

class SomeHandler(object)
    def __init__(self, successor=None):
        self.successor = successor

    def theMethod(self, theRequest):
        result = try_and_handle(theRequest)
        if did_not_handle(theRequest) and self.successor is not None:
            return successor.theMethod(theRequest)
        else:
            return result

#imagine some other handler classes
#setup:
masterHandler = SomeHandler(OtherHandler(ThirdHandler()))
#usage:
result = masterHandler.theMethod(aRequest)

So the *classes* don't ever know anything about each other; you pass a
handler class an instance of its successor handler at
construction-time. So there's no need for any registry or
introspection at all. You determine the ordering at runtime when you
construct the instances.

Of course, this entire pattern is usually unnecessary in Python as you
can usually write the same thing less verbosely and more
straightforwardly as:
def someHandler(theRequest):
    result = try_and_handle(theRequest)
    if did_not_handle(theRequest):
        return False, None
    else:
        return True, result

#imagine some other handler functions
#setup:
handlers = [someHandler, otherHandler, thirdHandler]
#usage:
for handler in handlers:
    success, result = handler(theRequest)
    if success: break

Note the lack of classes and how the sequencing is now made explicit.

Cheers,
Chris

Hi,
   Thank you very much Chris for the extremely quick and helpful
reply.
   I agree that it is not perfect CoR as per the examples given.. But,
I have done it very similar to the second example that you had given.
I needed classes because I am not doing just one thing - I have a lot
of pre-processing and post processing, so I had used classes. The
register methods etc are just a fancy way of creating the list as you
mentioned. I am using the registry because there are many procedures
wherein different methods of the classes in registry are being used.
   I am not sure whether I have understood your points completely. I
still cannot understand how to do the import so that the register
methods are hit.

The relationship should be between *instances* of the classes, not
among the *classes themselves directly*.
Each class is supposed to have a 'successor' instance variable that
its instances will delegate to if necessary. Reread my first code
sample and note how the "chain" is forged in the creation of
`masterHandler`.

Cheers,
Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top