1 / 108

Design Patterns in Java Chapter 3 Adapter

Design Patterns in Java Chapter 3 Adapter. Summary prepared by Kirk Scott. Adapter, Terminology and Statement of Pattern Intent. One code base is a client if it needs to make use of the functionality of methods in another code base, which would be the service provider

quinto
Download Presentation

Design Patterns in Java Chapter 3 Adapter

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. Design Patterns in JavaChapter 3Adapter Summary prepared by Kirk Scott

  2. Adapter, Terminology and Statement of Pattern Intent • One code base is a client if it needs to make use of the functionality of methods in another code base, which would be the service provider • Observe the possible sequence of events in large scale or disjointed development: • The client code is written before the service code, and the client makes calls to methods that do not end up in the service code base specifications and implementation

  3. Adapter, Terminology and Statement of Pattern Intent, cont’d. • Client and service code may also simply be written independently, without (advance) knowledge of each other’s interfaces • Or, the specifications for the code bases belong to different organizations and the differences between their interfaces are simply set in stone or fixed for other reasons • Whatever the reason, the scenario is that the service code contains useful functionality, and the underlying problem is that the client code was written to call methods by names that don’t exist in the service code

  4. This may sound like a screw-up and the the ideal solution might seem to be rewriting one or the other of the code bases so that the method names agree • However, if the specifications of the service code base have been set, recoding isn’t an option • Alternatively, once the code exists, recoding everything so that it agrees may be undesirable because it is too much work

  5. In a situation like this, the Adapter pattern can be used • The basic idea is that by insightful use of interfaces and subclasses, adding one class to the system makes it possible for the client code base to use the service code base

  6. There are actually several adapter scenarios • The simplest case is when the client code developer planned in advance for adaptation by implementing a Java interface of the necessary methods • There are other scenarios which fulfill the intent of adaptation but are somewhat different due to the absence of a Java interface or for other reasons

  7. Adapter, Terminology and Statement of Pattern Intent • Statement of Intent: • The intent of Adapter is to provide the interface that a client expects while using the services of a class with a different interface

  8. Adapting to an Interface • In the ideal case, the client developer realizes that services may eventually be required from another code base • The client developer then creates a Java interface which includes all of the methods which the client code calls

  9. An Adapter class implements this interface • The Adapter class also extends the class in the service code base which contains the useful methods • The implementation of the interface methods in the Adapter class are based on calls to the useful, but “misnamed” methods inherited from the superclass in the service code base

  10. The following diagram illustrates this basic version of the Adapter design pattern

  11. Concretely, the client makes use of an interface, RequiredInterface, which specifies the use of a method named requiredMethod() • The service code base contains an ExistingClass with a method named usefulMethod() which contains the needed functionality • The NewClass is an adapter which implements the interface and extends ExistingClass • In NewClass, the implementation of requiredMethod() is based on calls to usefulMethod()

  12. Before moving on, there is another aspect of this to consider • Apparently the book considers it obvious, but when reading the book, the question arose in my mind • In the diagram, the client is shown as making use of the interface by means of a line with an open arrowhead

  13. What does it mean for the client to make use of the interface? • Typically, you might think that the client code would contain calls of this sort: newClassObject.requiredMethod() • But this can’t be the case • The scenario is that the client doesn’t know about the contents of the service code base, and by definition, it would have been written before the adapter class was written

  14. How does the client “know” to use an object that conforms to the interface, or how does it acquire an object of a class that implements the interface? • Clearly, the client code cannot be rewritten to use objects of class NewClass • There are two parts to the answer to this question

  15. The first part of the answer is that although not explicitly shown, part of the use of the client consists of passing in references to objects • A reference to an object of NewClass could be passed into a method of the client code base • How can this be, if the client code does not “know about” NewClass? • Read on

  16. A second part of the answer is that the input parameter to a method of the client could be typed to the interface, not to a particular class • This is an approach that didn’t come up in CS 202, but it will recur in this book • Part of the power of interfaces is that they can be used as types

  17. If the client developer figured out the interface, then the client code can have objects and parameters typed to that interface wherever needed • Then truly, all that’s required for successful adaption is the creation of an adapter class that implements the interface • Wherever that interface is needed, references to the adapter class can be used

  18. A More Concrete Example • The book next explains more by working with specific example code • Oozinoz makes rockets, and in its code base is a class named EventSim, which runs simulations of rocket performance • The code base also includes the specifications for an interface, RocketSim, which represents rockets/rocket characteristics • EventSim was written to make use of the RocketSim interface • This is shown in the following UML diagram

  19. The foregoing description and diagram represent the client side of an illustration of the Adapter class • In addition, Oozinoz has a PhysicalRocket class which represents rockets • The PhysicalRocket class has a set of methods which are useful, and more or less analogous to the methods in the RocketSim interface • Unfortunately, they do not have the same names

  20. Suppose you would like to run EventSim and apply it to instances of the PhysicalRocket class • You can’t, but the situation is ripe for solution using the Adapter design pattern • The following UML diagram illustrates creating a new class, OozinozRocket, which implements the RocketSim interface and extends the PhysicalRocket class

  21. Notice that the methods on the client and server sides don’t agree exactly in name or other characteristics • Frequently there isn’t a simple one-to-one correspondence between methods with exactly the same function but different names • In this respect, the example is relatively realistic • Things are rarely rock bottom simple and the adapter will have to deal with the mismatch

  22. A brief overview reveals: • There are getMass() and getThrust() methods in both the interface and the class • However, these methods take a time parameter in the class methods and take no parameter in the interface

  23. There is also a setSimTime() method in the interface • It takes a time parameter • Recall that when implementing an interface, it is up to the programmer to supply any needed variables • They are not specified in the interface • This suggests that some sort of time variable will be lurking somewhere in the interface implementation

  24. There is also a getBurnTime() method in the server side class • It is not immediately apparent how this might be used to implement the interface methods in the Adapter class • On the other hand, it does seem like a potential source for the value of the time parameter

  25. Overall, domain knowledge (an explanation by the authors of how the simulation works) is needed in order to sort out the implementation of the Adapter class • The authors add that RocketSim keeps an internal clock (typical of event simulators) and occasionally updates simulated objects by calling the setSimTime() method

  26. When implementing the OozinozRocket Adapter class, it will be necessary to maintain a time instance variable which can be passed as a parameter to the PhysicalRocket class methods as needed • Although this really hardly seems like enough background information, the author now presents challenge 3.1 • As usual, lack of information is no problem—we’re just going to look immediately at the provided solution anyway and try to figure it out

  27. Challenge 3.1 • Complete the class diagram in Figure 3.3 to show the design of an OozinozRocket class that lets a PhysicalRocket object participate in a simulation as a RocketSim object. Assume that you can’t alter either RocketSim or Physical Rocket. • Note that although in a sense the warning “Thou shalt not alter” should go without saying, it is a useful reminder of the reality that the Adapter pattern is intended to address.

  28. Solution 3.1

  29. There are no surprises in the diagram shown • We were warned that a time variable would be needed • Also, all methods of the interface are shown in the Adapter class—as they should be • The only potentially unexpected thing is the inclusion of a constructor specification in the Adapter class • However, this also doesn’t contain surprises • It exactly parallels the constructor in the superclass

  30. The devil, then, is in the code writing • In other words, you know what methods you need to include; how do you write them? • Once again, domain knowledge will probably be necessary • In the simplest of all possible cases, it might be possible to wrap a call to a class method inside the body of an interface method

  31. On the other hand, it may also be necessary to write more complex implementations of the interface methods in order to make successful use of the functionality in the class methods • The authors next give partial code for the Adapter class, leaving the implementations of two of the methods as challenges

  32. package com.oozinoz.firework; • import com.oozinoz.simulation.*; • public class OozinozRocket • extends PhysicalRocket • implements RocketSim • { • private double time;

  33. public OozinozRocket • (double burnArea, double burnRate, • double fuelMass, double totalMass) • { • super(burnArea, burnRate, • fuelMass, totalMass); • }

  34. public double getMass() • { • // Challenge! • } • public double getThrust() • { • // Challenge! • } • public void setSimTime(double time) • { • this.time = time; • } • Note the use of this.time = time • This is an evil aberration from all that’s right and good and true…

  35. Challenge 3.2 • Complete the code for the OozinozRocket class, including methods getMass() and getThrust().

  36. Before looking at the solution, consider these two observations • 1. Obviously you don’t have to implement getBurnTime() • It’s a method in the class, not the interface, and it’s inherited • It also turns out that it plays no role in the implementation of the interface methods

  37. 2. The solution turns out to be deceptively simple • Although the worst-case scenario is that the client developer has no advance knowledge, it seems that in this case the client developer knew or foresaw something about the service code base • The interface includes the setSimTime() method

  38. Formally, there is no indication in the specifications of the getMass() and getThrust() methods of the interface that a simulation time would be needed in order to implement those methods • However, if you look at the PhysicalRocket class and see that the analogous methods require a time parameter, then it becomes necessary to support a time variable in the interface and provide a method for setting its value

  39. Solution 3.2 • public double getMass() • { • return getMass(time); • } • public double getThrust() • { • return getThrust(time); • }

  40. Just to state the obvious, both getMass() and getThrust() are overloaded in the Adapter class • The class inherits the versions which take parameters and implements the versions which don’t • The example ultimately turns out to be an example of the simplest kind, once you understand the treatment of the time variable

  41. The interface versions of the methods don’t have a time parameter • The server code versions of the methods do have a time parameter • In the adapter code, a call to the client method is wrapped inside the implementation of the adapter version of the method

  42. Class and Object Adapters • The approach illustrated previously is know more specifically as a class adapter • This is the case where you implement a client interface and extend a service class • A different approach has to be taken if the client code base does not specify a particular interface • In this second case it’s necessary to create what is known as an object adapter

  43. When implementing an object adapter, the idea is that rather than a Java interface in the client code, there is a class with a set of methods that need to be supported • The object adapter approach is to make a subclass of the client code class and then make use of an object of the service code base to help implement the methods of the subclass • Take a look at the following UML diagram

  44. The book describes the object adapter, the NewClass, as adapting by means of delegation • Observe that NewClass is connected to ExistingClass by means of a navigability arrow • This means that NewClass has a reference to an object of ExistingClass and can call ExistingClass methods on that object as part of the code implementing the methods in NewClass • The idea is that the methods in NewClass override the methods in RequiredClass, providing the needed functionality by means of calls on ExistingClass objects

  45. Note that the class adapter and object adapter UML diagrams are different • That is to say, the structure of these two different kinds of adapters is not the same • However, they are both classified as the adapter pattern because their intent is exactly the same • They differ structurally because in the adapter case the client provides an interface and in the object case the client provides a class • It will also become evident later that there are other reasons or cases whether the object adapter is desirable

  46. In the previous example, EventSim was the client, and it made use of the predefined RocketSim interface • This made it possible for the OozinozRocket class to be written to adapt to the existing PhysicalRocket class

More Related