Join Jungwoo Ryoo for an in-depth discussion in this video Chain of responsibility example, part of Python: Design Patterns.
- Let's start by first defining our handler class, which is an abstract handler. Since the point of a handler is to find the successor, if the current handler is not able to handle the request we need an attribute to store a successor handler. So, type self._ successor =, and the successor handler is coming in as an argument in the init method, as you can see here.
So, the name of it is successor, s-u-c-c-e-s-s-o-r. So the next method is this handle method, and in the handle method we'll first try to handle the request and see what happens. To handle the request, we simply cull, _handle method. So, just type self._handle, and then the request.
So, when we invoke this _handle method it will try to handle the request. If it is able to handle the request it will return this True value. So, this variable handled will be initialized to have a True value if the handling was successful. So the next part of our code is checking this valued in the handled variable, as you can see here. So, if the _handle request method couldn't handle the request, then we have to do something else.
Then, we'll having to be using a successor. That's why we type self._sucessor, so now we're using the successor handler, .handle. So, we use the handle method on the successor handler object. And then we pass the request. And this _handle method provides an interface to be implemented by these concrete handler classes.
So now, let's go ahead and define our concrete handler classes. In our first concrete handler definition or concretehandler1 definition, you see this conditional statement. So, if the request is in between zero and 10, then it will print this message, "Request so-and-so handled in hander 1" and then it will return this True value to the culler of the method.
So, basically indicating the request was handled properly. The next concrete handler class is default handler class, in which we'll try to be covering the case no handler can handle the request. So, that's one of the reasons why we don't have any conditional statement in the _handle method. So, no matter what, we'll be alway printing this message, simply saying "End of chain, no handler for such-and-such," and it will always return this True value, just to make sure then handling process is over.
Finally, we have this client class, which is using the handlers. So, this is what is actually using the handler classes. In the client class, we'll be creating handlers first, and then we'll try to use them in a sequence we want. So, let's create our handler by typing concretehandler, but the concrete handler needs to specify who is its successor, that's why we will be using the default handler as a successor.
DefautHandler... And the default handler has no successor, which is why we use None here. And then we'll store the instance of the concrete handler in this variable called Handler. So that's why we type self.handler = The next part of this client class is this delegate method. And in the delegate method, all we're doing is receiving the requests, and then, based on the number of requests in this request list, we'll be iterating through this requests list, and then we'll try handle these requests one at a time.
So that's what's happening in the forelook. So, we're finally done with the definition of all the classes we need, and now we're ready to move on to actually using these classes. So, let's use them by first creating a client. So, type c = Client, and then we'll have to be providing the request in the form of a list, so we'll be using some integers as requests. We'll be using two, five, and then maybe 30.
Let's scroll down. And then, we'll be invoking this delegate method on the client object. C.delegate and then we'll have to pass the request. Now let's go ahead and run the script. Tools, Build. So, it looks like we have a little bit of typo. There is no such thing as concrete handler because our concrete handler was concretehandler1, so we'll be typing 1 there, and then try again.
And the script works fine. Now, remember that this chain of responsibility pattern is used not to tie a specific solution to a request, and I hope I demonstrated this well in the code.
- Understanding design patterns
- Best design practices: consistency, completeness, and correctness
- Working with creational patterns
- Working with structural patterns
- Working with behavioral patterns
Skill Level Intermediate
Q: In the strategy pattern example, why does the code keep executing the default function rather than the alternate?
A: The programming demonstration skips the step of defining what the strategy pattern should be when an alternate function name is provided
as an argument as shown below.