1 / 100

Chapter 12 Chain of Responsibility

Chapter 12 Chain of Responsibility. Summary prepared by Kirk Scott. Design Patterns in Java Chapter 12 Chain of Responsibility. Summary prepared by Kirk Scott. Introduction Before the Introduction. One general goal of a good object-oriented design is loose coupling

sinjin
Download Presentation

Chapter 12 Chain of Responsibility

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 12Chain of Responsibility Summary prepared by Kirk Scott

  2. Design Patterns in JavaChapter 12Chain of Responsibility Summary prepared by Kirk Scott

  3. Introduction Before the Introduction • One general goal of a good object-oriented design is loose coupling • The idea is that changes in one area of the design won’t require changes in other areas • Encapsulation in Java provides a certain degree of loose coupling • Client objects are insulated from changes in class implementation code as long as the set of public methods remains the same

  4. Inheritance, polymorphism, and dynamic binding all in their own way support loose coupling • Client code doesn’t have to know where in an inheritance hierarchy a method is implemented • Client code can call methods on superclass references or objects of classes that implement a given interface

  5. On the other hand, you’ve also seen code where it can be useful to call getClass(), for example, to find out what class an object is an instance of • The use of that method emphasized this simple fact of programming, which was already clear: • In order to call a method, in general, you need to know what kind of object you are trying to call it on

  6. This reflects a kind of coupling: • The client has to know which class/object it’s working with • Or viewed another way, the client has to know which class/object actually has the method containing the functionality it wants to use

  7. This kind of coupling can be loosened in certain kinds of software designs • For example, the objects in a design may be in some sort of relationship where a call made on one object can be satisfied by a call “through” to another • In other words, one object will have the method, so that the call can be made on it • However, the implementation of the method depends on the existence of the functionality in another class that the call is passed to

  8. The book gives a prototypical example of the kind of relationship where calls are passed • This example is when objects are related in a tree structure • Calls to one object can be passed “up the tree” until they can be satisfied

  9. Notice that this is a responsibility pattern • You decrease the coupling between the client and the base objects it uses • In other words, the client can merrily call the desired method on (potentially many different) objects, not knowing how the functionality is achieved, as usual

  10. However, you offload responsibility from one base object that is called to another which provides the functionality • This means that there is increased coupling among the base objects in the design

  11. Book Definition of Pattern • Book definition: • The intent of the Chain of Responsibility pattern is to avoid coupling the sender of a request to its receiver, by giving more than one object a chance to handle the request.

  12. More Preliminary Ideas • Think about how inheritance works again • A subclass either inherits a method or overrides it • If it overrides it, it has the ability to buck the call upwards using super

  13. Now consider the chapter on composites again • The whole idea there was that a set of objects ended up in a tree-like, or hierarchical relationship • However, this was not an is-a or is-a-kind-of inheritance relationship • It was a has-a relationship

  14. Recall that in UML the composition symbol, the diamond, represents a has-a relationship • Using that terminology, what is under consideration now is a composition relationship • The Chain of Responsibility design pattern is intended for use in this kind of situation

  15. In the original composite pattern, an instance of the composite class “has an” instance of the component class • This means that the parent of the has-a relationships knows about its children • In the scenario under consideration it’s necessary to buck things up the hierarchy • This will require including a link, or reference, so that a child in a has-a relationship knows who its parent is

  16. One last general remark • Even though the name of the pattern is Chain of Responsibility, all of the concrete examples will be of the form “Tree of Responsibility” • …Of course, there is no such thing as a tree of responsibility

  17. Random association comment mode on: • Tree of life? • Chaingang of love? • Web of deceit?

  18. In theory, the internal relationships of a set of classes in a has-a relationships could be of any kind • As long as there was a discernible logic to the relationships and responsibilities it would be possible to implement some sort of chain of responsibility in the structure

  19. A linked list or a doubly linked list could have a chain of responsibility, for example • A call to one object would be bucked to its neighbor until the method returned the desired result

  20. An Ordinary Chain of Responsibility • The authors begin describing the pattern with a concrete example • In a factory setting, various machines may have specific engineers assigned to them • A sufficiently important or complicated machine may have its own engineer • A simpler machine which is part of a composition of machines may have as its engineer the engineer assigned to the composition of machines that it belongs to

  21. From the design pattern point of view, the software goal can be described as follows: • Suppose client code is trying to find the engineer assigned to a given machine • It is desirable for the client code only to have to make one call

  22. This is the undesirable scenario: • The client code makes the call • The call returns null, or some other value indicating lack of success • The client then has to make a call to obtain a reference to the parent • The client then makes the call on the parent • This could continue an arbitrary number of times, from parent to grandparent and so on

  23. In other words, you don’t want the client code cluttered up in this way: • Make a call to get the engineer of an object • If not successful, make a call to get the parent of an object • Make a call to get the engineer of the parent • If not successful, make a call to get the parent of the parent • …

  24. Suppose that the method for getting the responsible engineer is getResponsible() • You’d like the composition hierarchy to be structured so that the client code simply has to call getResponsible() on an object • If the object doesn’t have an engineer directly assigned to it, in the implementation of getResponsible() there is a call to getResponsible() on the object’s parent

  25. Notice that this is reminiscent of recursion • The respective calls to getResponsible() work their way up a has-a tree until they reach the root • The root case will be considered later • The book’s UML diagram of the composite under consideration is shown on the next overhead • Note that getResponsible() returns an instance of the Engineer class • Note also that getResponsible() is inherited, not overridden

  26. Note that the MachineComponent class has a responsible:Engineer instance variable as well as a getResponsible():Engineer method • There is no requirement that the responsible instance variable not be null • In the code, if(responsible == null) would be the trigger for calling getResponsible() on the parent object

  27. Challenge 2.1 • “Point out two weaknesses of the design shown in Figure 12.1.” • Comment mode on: They point out more than two. • Take your pick…

  28. Solution 12.1 • “Some potential disadvantages of the Chain of Responsibility design that Oozinoz uses for finding a machine’s responsible engineer include the following.

  29. “1. We haven’t specified how the chain will be set up so that machines know their parent. • In practice, it may be difficult to ensure that parents are never null.”

  30. Comment mode on: • Note that this is talking about null parents, not null responsible engineers. • What they’re saying is related to what happened with the composite examples: • How do you know that the (tree) structure is set up correctly? • How do you know you have at least one parent as well as no more than one parent?

  31. “2. It is conceivable that the search for a parent could enter an infinite loop, depending on how the parents are set up.” • [This is the same situation as in the previous point • The tree structure could be incorrectly set up and contain a cycle, for example.]

  32. “3. Not all objects have all the behaviors implied by these new methods. • (For example, the top level item has no parent.)” • [This is related to the previous points • How do you know you have a correctly structured tree? • Also, how do you deal with the fact that the root node of a tree is special?]

  33. “4. The present design is light on details regarding how the system knows which engineers are currently in the factory and available. • It’s not clear how “real time” this responsibility needs to be.” • [End of challenge solution.]

  34. The book says the following: • This pattern helps simplify code when it’s not obvious which object in a group should handle a request. • Stated more accurately, this pattern helps when there is an internal logic to which object might handle a request • If there is an internal pattern, using the design pattern might make client code considerably easier to write

  35. Refactoring to Chain of Responsibility • One sign that code might benefit from the chain of responsibility design pattern is when client code makes “probing” calls • In the absence of the design pattern, the assumption would be that every class implements the desired method • Depending on the situation, the method might return null when called on some objects

  36. The book restates the idea of the pattern in this way: • To implement the design pattern, make sure that every class in question implements the method—with a chaining strategy for those that can’t return a value • In other words, you want to write code so that you don’t have situations where a call to the method simply returns null

  37. Tools and Tool Carts • The book wants to introduce an example where some kinds of objects can never satisfy a call to getResponsible() without passing the call on to their parents • The book illustrates this extension by adding tools and tool carts to the design scenario

  38. Tool carts have engineers assigned to them, like machines do • Individual tools do not have engineers assigned to them • The engineer assigned to a tool is always the engineer assigned to the cart that the tool belongs to

  39. Tools and tool carts are a somewhat unfortunate addition to the example • You might assume that a tool cart was treated as a “composite machine” and a tool was a “leaf machine” • They are not integrated into the composite hierarchy in this way

  40. The Visualization Interface • The tool and tool cart ideas are integrated with the machine composite hierarchy by introducing a new interface into the example • The elements of a graphical application would have a visual representation • These visual elements might include machine composites, tool carts, and tools

  41. Client code would make use of objects that implemented a VisualizationItem interface • Both machine related items and tool related items implement this interface • The UML diagram on the following overhead shows the scenario

  42. This UML diagram is for an un-refactored design • MachineComponent, ToolCart, and Tool all implement the VisualizationItem interface • getResponsible() is not declared in the VisualizationItem interface, so not all classes that implement it would need getResponsible()

  43. MachineComponent has getResponsible() based on previous discussion • Machine and MachineComposite have it by inheritance • ToolCart is also shown as having getResponsible() • The Tool class doesn’t have that method

  44. The AmbitiousMenu • In client code, it will be necessary to check which kind of object you’re working with before calling getResponsible() • Code will be shown for an AmbitiousMenu class which calls getResponsible() on various kinds of visualization objects, like machines and tools • This has to be done with a series of if statements, “probing” code, because not all of the classes implement getResponsible()

More Related