1 / 31

Where Were We?

Where Were We?. Attempting to spray ants with ant poison and (generic) insects with generic spray If there is not a complete match between the signatures of methods in base and derived classes there is no polymorphism Compiler determines the call by using the declared type Now apply this.

Télécharger la présentation

Where Were We?

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. Where Were We? • Attempting to spray ants with ant poison and (generic) insects with generic spray • If there is not a complete match between the signatures of methods in base and derived classes there is no polymorphism • Compiler determines the call by using the declared type • Now apply this

  2. public class Poison{ public void spray(Insect aBug){ System.out.println(“Generic Spray”); } public void spray(Ant antBug){ System.out.println(“Generic Ant Spray”); } }; public class AntPoison extends Poison{ public void spray(Ant antBug){ System.out.println(“Spraying Ant with Ant spray”); } };

  3. Remarks • It appears that we are attempting to use polymorphism both on the Poison type and the Insect type • The only polymorphism that will work is with a static reference to Poison (and a run-time reference to either Poison or AntPoison) and a static reference to Ant. Period

  4. Test This Poison container = new AntPoison(); Insect bugType = new Ant(); container.spray(bugType); bugType = new Insect(); container.spray(bugType); Produces Generic Spray Generic Spray

  5. public class Poison{ public void spray(Insect aBug){ System.out.println(“Generic Spray”); } public void spray(Ant antBug){ System.out.println(“Generic Ant Spray”); } }; public class AntPoison extends Poison{ public void spray(Ant antBug){ System.out.println(“Spraying Ant with Ant spray”); } };

  6. Why? • Because there is no spray method in Ant with an insect parameter • But, calling Poison container = new AntPoison(); Container.spray(new Ant()); Container.spray(new Insect());

  7. Results • Produces Spraying ant with ant spray Generic spray • Which at least works on ants. • Doesn’t work properly on insects

  8. Use Polymorphism Properly • Can’t use 2 different container references and 2 different parameter references at one time • Do it in two steps • Bounce from the Poison class to the Insect class using beingSprayed() methods in all classes • Make use of this, because it is statically determined

  9. Fix up Insect public class Poison{ public void spray (Insect aBug){ System.out.println(“Generic Spray”); aBug.beingSprayed(this); } } public class AntPoison{…} //no //being Sprayed

  10. Put in the Bounce Call public class Insect{ public void beingSprayed(Poison aPoison){ System.out.println(“Insect sprayed with poison”);} Public class Ant extends Insect{ public void beingSprayed(Poison aPoison){ System.out.println(“Ant sprayed with poison”); }}

  11. Note • Because we used this, the actual parameter of beingSprayed is always of type Poison • Insect is now working correctly

  12. Test Poison container = new AntPoison(); Insect aBug = new Ant(); container.spray(aBug); aBug = new Insect(); container.spray(aBug); Produces Generic Spray Ant being sprayed with poison Generic Spray Insect being sprayed with poison

  13. Problem • We are only spraying with generic poison • In order to make use of a spray method in the AntPoison class we must repeat the spray() method with exactly the same signature in the AntPoison derived class • Furthermore, we need a beingSprayed() method of each poison type in both Insect and Ant

  14. public class Poison{ public void spray(Insect aBug){ aBug.beingSprayed(this); } } ; public class AntPoison extends Poison{ public void spray(Insect aBug){ aBug.beingSprayed(this); } };

  15. public class Insect{ public void beingSprayed(Poison aPoison){ System.out.println(“Insect sprayed with generic poison”); } public void beingSprayed(AntPoison aPoison){ System.out.println(“Insect sprayed with ant poison”); } }; Public class Ant extends Insect{ public void beingSprayed(Poison aPoison){ System.out.println(“Ant sprayed with generic poison”); } public void beingSprayed(AntPoison aPoison){ System.out.println(“Ant sprayed with ant poison”); } };

  16. Remarks • To insure polymorphism after the bounce Insect and Ant must have 2 beingSprayed() methods with different signatures (i.e. parameters) • To have the ability to use ant poison the spray() method is repeated with the same signature in both Insect and Ant

  17. Let’s Test This Poison container = new AntPoison(); Insect aBug = new Ant(); container.spray(aBug); aBug = new Insect(); container.spray(aBug); Poison container = new Poison(); Insect aBug = new Ant(); container.spray(aBug); aBug = new Insect(); container.spray(aBug);

  18. Hooray! Ant sprayed with ant poison Insect sprayed with ant poison Ant sprayed with generic poison Insect sprayed with generic poison

  19. What we Have Poison Insect beingSprayed(Poison) Spray(Insect) beingSprayed(AntPoison) AntPoison Ant beingSprayed(Poison) Spray(Insect) beingSprayed(AntPoison) • Methods in Poison and AntPoison are identical!! • Note output in Insect classes--Insect shouldn’t know anything about Poison

  20. One Way Out • Let the beingSprayed methods call other methods inthe Poison classes • Call them sprayIt() • Param types are with Insect and Ant • Put the print statements into the Poison (Visitor) classes

  21. We Obtain Poison Insect Spray(Insect) beingSprayed(Poison) SprayIt(Insect) SprayIt(Ant) print statements Ant AntPoison beingSprayed(Poison) SprayIt(Insect) SprayIt(Ant) Visitor Object Structure

  22. Now Simplify • The above is the general solution to double dispatch • It is too general for our purposes • Make Insect and Poison abstract • Begin with the Object Structure and eliminate Spray() from Poison • SprayIt(Insect) is never called, so eliminate • We obtain

  23. Poison Insect beingSprayed(Poison) SprayIt(Ant) Ant Ant beingSprayed(Poison) SprayIt(Ant) Visitor Object Structure Poison.sprayIt(this)

  24. Now Add the Roaches • Call beingSprayed() sprayAnt(), because Insect is abstract • You will need 2 methods, sprayAnt(Ant) as well as sprayRoach(Roach) in Poison • Note the excess baggage, e.g. spraying a roach with ant poison

  25. The Visitor Pattern • Is a GoF Pattern • Purpose: To implement operations on the objects of a structure without keeping those operations in the object themselves • Key Idea: The operations that are executed depend on both the type of the operation and the type of the node to which it is applied • Advantage: Extension is dead easy • Disadvantage: Methods grow like weeds

  26. In Our Case • Insectis the object structure • Poison is the visitor • Note the duplication in code—dangerous! • The Insect classes have to know about the Poison classes • There is a better way! • Do a double bounce

  27. Structure of the Visitor Poison sprayAnt(Ant); sprayRoach(Roach); AntPoison sprayAnt(Ant); sprayRoach(Roach); RoachPoison sprayAnt(Ant); sprayRoach(Roach);

  28. The Visitor Pattern • Main idea: use an iterator or traversal to visit each node of the object structure and visit it with the corresponding node of the visitor structure • The object structure classes have no knowledge of the visitor classes • What gets carried out depends on two things • The type of the visitor • The type of the object node • Hence double dispatch

  29. Object Structure Visited Insect getSprayed(Poison); Ant getSprayed(Poison p) Roach getSprayed(Poison p) p.sprayAnt(this); p.sprayRoach(this);

  30. Structure of the Visitor Pattern Visitor VisitConcreteElementA(ConcreteElementA) VisitConcreteElementB(ConcreteElementB) ConcreteVisitor1 ConcreteVisitor2 VisitConcreteElementA(ConcreteElementA) VisitConcreteElementA(ConcreteElementA) VisitConcreteElementB(ConcreteElementB) VisitConcreteElementB(ConcreteElementB) The Visitor

  31. Object Structure Element ObjectStructure Accept(Visitor) ConcreteElementA ConcreteElementA Accept(Visitor v) Accept(Visitor v) OperationA() OperationB() v->VisitConcreteElementA(this) v->VisitConcreteElementB(this)

More Related